blob: 56cc73f362a65a0c90a598b83769834c8f9baf1e [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/vr/openvr/openvr_gamepad_helper.h"
#include <memory>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/vr_device.h"
#include "third_party/openvr/src/headers/openvr.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/transform_util.h"
namespace device {
namespace {
mojom::XRGamepadButtonPtr GetGamepadButton(
const vr::VRControllerState_t& controller_state,
uint64_t supported_buttons,
vr::EVRButtonId button_id) {
uint64_t button_mask = vr::ButtonMaskFromId(button_id);
if ((supported_buttons & button_mask) != 0) {
auto ret = mojom::XRGamepadButton::New();
bool button_pressed = (controller_state.ulButtonPressed & button_mask) != 0;
bool button_touched = (controller_state.ulButtonTouched & button_mask) != 0;
ret->touched = button_touched;
ret->pressed = button_pressed;
ret->value = button_pressed ? 1.0 : 0.0;
return ret;
}
return nullptr;
}
} // namespace
mojom::XRGamepadDataPtr OpenVRGamepadHelper::GetGamepadData(
vr::IVRSystem* vr_system) {
mojom::XRGamepadDataPtr ret = mojom::XRGamepadData::New();
vr::TrackedDevicePose_t tracked_devices_poses[vr::k_unMaxTrackedDeviceCount];
vr_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0.0f,
tracked_devices_poses,
vr::k_unMaxTrackedDeviceCount);
for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i) {
if (vr_system->GetTrackedDeviceClass(i) !=
vr::TrackedDeviceClass_Controller)
continue;
vr::VRControllerState_t controller_state;
bool have_state = vr_system->GetControllerState(i, &controller_state,
sizeof(controller_state));
if (!have_state)
continue;
auto gamepad = mojom::XRGamepad::New();
gamepad->controller_id = i;
gamepad->timestamp = base::TimeTicks::Now();
vr::ETrackedControllerRole hand =
vr_system->GetControllerRoleForTrackedDeviceIndex(i);
switch (hand) {
case vr::TrackedControllerRole_Invalid:
gamepad->hand = device::mojom::XRHandedness::NONE;
break;
case vr::TrackedControllerRole_LeftHand:
gamepad->hand = device::mojom::XRHandedness::LEFT;
break;
case vr::TrackedControllerRole_RightHand:
gamepad->hand = device::mojom::XRHandedness::RIGHT;
break;
}
uint64_t supported_buttons = vr_system->GetUint64TrackedDeviceProperty(
i, vr::Prop_SupportedButtons_Uint64);
for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) {
int32_t axis_type = vr_system->GetInt32TrackedDeviceProperty(
i,
static_cast<vr::TrackedDeviceProperty>(vr::Prop_Axis0Type_Int32 + j));
switch (axis_type) {
case vr::k_eControllerAxis_Joystick:
case vr::k_eControllerAxis_TrackPad: {
gamepad->axes.push_back(controller_state.rAxis[j].x);
gamepad->axes.push_back(controller_state.rAxis[j].y);
auto button = GetGamepadButton(
controller_state, supported_buttons,
static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + j));
if (button) {
gamepad->buttons.push_back(std::move(button));
}
} break;
case vr::k_eControllerAxis_Trigger: {
auto button = mojom::XRGamepadButton::New();
button->value = controller_state.rAxis[j].x;
uint64_t button_mask = vr::ButtonMaskFromId(
static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + j));
if ((supported_buttons & button_mask) != 0) {
button->pressed =
(controller_state.ulButtonPressed & button_mask) != 0;
}
gamepad->buttons.push_back(std::move(button));
} break;
}
}
auto button =
GetGamepadButton(controller_state, supported_buttons, vr::k_EButton_A);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_Grip);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_ApplicationMenu);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_DPad_Left);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_DPad_Up);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_DPad_Right);
if (button)
gamepad->buttons.push_back(std::move(button));
button = GetGamepadButton(controller_state, supported_buttons,
vr::k_EButton_DPad_Down);
if (button)
gamepad->buttons.push_back(std::move(button));
const vr::TrackedDevicePose_t& pose = tracked_devices_poses[i];
if (pose.bPoseIsValid) {
const vr::HmdMatrix34_t& mat = pose.mDeviceToAbsoluteTracking;
gfx::Transform transform(
mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0],
mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1],
mat.m[2][2], mat.m[2][3], 0, 0, 0, 1);
gfx::DecomposedTransform src_pose;
gfx::DecomposeTransform(&src_pose, transform);
auto dst_pose = mojom::VRPose::New();
dst_pose->orientation = std::vector<float>(
{src_pose.quaternion.x(), src_pose.quaternion.y(),
src_pose.quaternion.z(), src_pose.quaternion.w()});
dst_pose->position =
std::vector<float>({src_pose.translate[0], src_pose.translate[1],
src_pose.translate[2]});
dst_pose->angularVelocity = std::vector<float>(
{pose.vAngularVelocity.v[0], pose.vAngularVelocity.v[1],
pose.vAngularVelocity.v[2]});
dst_pose->linearVelocity = std::vector<float>(
{pose.vVelocity.v[0], pose.vVelocity.v[1], pose.vVelocity.v[2]});
gamepad->pose = std::move(dst_pose);
}
ret->gamepads.push_back(std::move(gamepad));
}
return ret;
}
} // namespace device