// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_VR_OPENXR_OPENXR_CONTROLLER_H_
#define DEVICE_VR_OPENXR_OPENXR_CONTROLLER_H_
#include <stdint.h>
#include <string.h>
#include <map>
#include <optional>
#include <unordered_map>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "device/gamepad/public/cpp/gamepad.h"
#include "device/vr/openxr/openxr_hand_tracker.h"
#include "device/vr/openxr/openxr_interaction_profiles.h"
#include "device/vr/openxr/openxr_path_helper.h"
#include "device/vr/public/mojom/openxr_interaction_profile_type.mojom.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
#include "ui/gfx/geometry/transform.h"
namespace device {
class OpenXrExtensionHelper;
class OpenXrController {
public:
OpenXrController();
OpenXrController(const OpenXrController&) = delete;
OpenXrController& operator=(const OpenXrController&) = delete;
~OpenXrController();
// The lifetime of OpenXRInputHelper is a superset of OpenXRController. Thus
// we may safely pass the OpenXRPathHelper of the parent class to
// OpenXRController as a dependency.
XrResult Initialize(
OpenXrHandednessType type,
XrInstance instance,
XrSession session,
const OpenXRPathHelper* path_helper,
const OpenXrExtensionHelper& extension_helper,
bool hand_input_enabled,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
XrActionSet action_set() const { return action_set_; }
mojom::XRInputSourceDescriptionPtr GetDescription(
XrTime predicted_display_time);
std::optional<GamepadButton> GetButton(OpenXrButtonType type) const;
std::optional<Gamepad> GetWebXRGamepad() const;
std::optional<gfx::Transform> GetMojoFromGripTransform(
XrTime predicted_display_time,
XrSpace local_space,
bool* emulated_position) const;
// Returns true if this controller can supply HandTracking data.
bool IsHandTrackingEnabled() const;
mojom::XRHandTrackingDataPtr GetHandTrackingData();
// Specifically update just the interaction profile. Will not update any other
// data.
XrResult UpdateInteractionProfile();
XrResult Update(XrSpace base_space, XrTime predicted_display_time);
private:
XrResult InitializeControllerActions();
XrResult InitializeControllerSpaces();
XrResult SuggestBindings(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) const;
XrResult SuggestBindingsForButtonMaps(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings,
const std::vector<OpenXrButtonPathMap>& button_maps,
XrPath interaction_profile_path,
const std::string& binding_prefix) const;
XrResult CreateActionsForButton(OpenXrButtonType button_type);
XrResult CreateAction(XrActionType type,
const std::string& action_name,
XrAction* action);
XrResult CreateActionSpace(XrAction action, XrSpace* space);
XrResult SuggestActionBinding(
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings,
XrPath interaction_profile_path,
XrAction action,
std::string binding_string) const;
bool IsCurrentProfileFromHandTracker() const;
std::optional<gfx::Transform> GetGripFromPointerTransform(
XrTime predicted_display_time) const;
mojom::XRTargetRayMode GetTargetRayMode() const;
mojom::XRHandedness GetHandness() const;
std::vector<double> GetAxis(OpenXrAxisType type) const;
template <typename T>
XrResult QueryState(XrAction action, T* action_state) const {
// this function should never be called because each valid XrActionState
// has its own template function defined below.
NOTREACHED_IN_MIGRATION();
return XR_ERROR_ACTION_TYPE_MISMATCH;
}
template <>
XrResult QueryState<XrActionStateFloat>(
XrAction action,
XrActionStateFloat* action_state) const {
action_state->type = XR_TYPE_ACTION_STATE_FLOAT;
XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
get_info.action = action;
return xrGetActionStateFloat(session_, &get_info, action_state);
}
template <>
XrResult QueryState<XrActionStateBoolean>(
XrAction action,
XrActionStateBoolean* action_state) const {
action_state->type = XR_TYPE_ACTION_STATE_BOOLEAN;
XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
get_info.action = action;
return xrGetActionStateBoolean(session_, &get_info, action_state);
}
template <>
XrResult QueryState<XrActionStateVector2f>(
XrAction action,
XrActionStateVector2f* action_state) const {
action_state->type = XR_TYPE_ACTION_STATE_VECTOR2F;
XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
get_info.action = action;
return xrGetActionStateVector2f(session_, &get_info, action_state);
}
template <>
XrResult QueryState<XrActionStatePose>(
XrAction action,
XrActionStatePose* action_state) const {
action_state->type = XR_TYPE_ACTION_STATE_POSE;
XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
get_info.action = action;
return xrGetActionStatePose(session_, &get_info, action_state);
}
mojom::XRInputSourceDescriptionPtr description_;
OpenXrHandednessType type_;
XrInstance instance_;
XrSession session_;
XrActionSet action_set_;
XrAction grip_pose_action_;
XrSpace grip_pose_space_;
XrAction pointer_pose_action_;
XrSpace pointer_pose_space_;
std::unique_ptr<OpenXrHandTracker> hand_tracker_;
mojom::OpenXrInteractionProfileType interaction_profile_;
std::unordered_map<OpenXrButtonType,
std::unordered_map<OpenXrButtonActionType, XrAction>>
button_action_map_;
std::unordered_map<OpenXrAxisType, XrAction> axis_action_map_;
raw_ptr<const OpenXRPathHelper, DanglingUntriaged> path_helper_;
raw_ptr<const OpenXrExtensionHelper> extension_helper_;
bool hand_joints_enabled_ = false;
};
} // namespace device
#endif // DEVICE_VR_OPENXR_OPENXR_CONTROLLER_H_