Files
flightgear/3rdparty/osgXR/src/OpenXR/Action.h
T
2022-10-20 20:29:11 +08:00

372 lines
8.3 KiB
C++

// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2021 James Hogan <james@albanarts.com>
#ifndef OSGXR_OPENXR_ACTION
#define OSGXR_OPENXR_ACTION 1
#include "ActionSet.h"
#include "Path.h"
#include <osg/Vec2f>
#include <osg/ref_ptr>
#include <cassert>
#include <string>
#include <vector>
namespace osgXR {
namespace OpenXR {
class Path;
class Space;
class Action : public osg::Referenced
{
public:
Action(ActionSet *actionSet,
const std::string &name,
const std::string &localizedName,
XrActionType type);
virtual ~Action();
// Action initialisation
void addSubaction(const Path &path);
// Returns true on success
bool init();
// Error checking
inline bool valid() const
{
return _action != XR_NULL_HANDLE;
}
inline bool check(XrResult result, const char *warnMsg) const
{
return _actionSet->check(result, warnMsg);
}
// Conversions
inline const osg::ref_ptr<ActionSet> getActionSet() const
{
return _actionSet;
}
inline const osg::ref_ptr<Instance> getInstance() const
{
return _actionSet->getInstance();
}
inline XrInstance getXrInstance() const
{
return _actionSet->getXrInstance();
}
inline XrActionSet getXrActionSet() const
{
return _actionSet->getXrActionSet();
}
inline XrAction getXrAction() const
{
return _action;
}
protected:
// Action data
osg::ref_ptr<ActionSet> _actionSet;
std::vector<XrPath> _subactionPaths;
XrActionCreateInfo _createInfo;
XrAction _action;
};
/// Base action state for inputs.
class ActionStateBase : public osg::Referenced
{
public:
// Constructors
ActionStateBase(Action *action, Session *session,
Path subactionPath = Path());
virtual ~ActionStateBase();
// Error checking
inline bool valid() const
{
return _valid;
}
inline bool check(XrResult result, const char *warnMsg) const
{
return _action->check(result, warnMsg);
}
protected:
// Utilities for synchronisation
// Find whether the state needs update and update sync counter
bool checkUpdate();
// Member data
osg::ref_ptr<Action> _action;
osg::ref_ptr<Session> _session;
Path _subactionPath;
bool _valid;
unsigned int _syncCount;
};
/// All action states have an isActive field.
template <typename T>
class ActionStateCommon : public ActionStateBase
{
private:
typedef ActionStateBase Base;
public:
// Constructors
ActionStateCommon(Action *action, Session *session,
Path subactionPath = Path()) :
Base(action, session, subactionPath)
{
}
// Accessors
bool isActive() const
{
assert(valid());
return _state.isActive;
}
// Operations
/// Update state if a sync has taken place
bool update()
{
if (Base::checkUpdate())
return updateState();
return valid();
}
protected:
// Protected operations
bool updateState();
// Data members
T _state;
};
// These are the base action state classes
typedef ActionStateCommon<XrActionStateBoolean> ActionStateCommonBoolean;
typedef ActionStateCommon<XrActionStateFloat> ActionStateCommonFloat;
typedef ActionStateCommon<XrActionStateVector2f> ActionStateCommonVector2f;
typedef ActionStateCommon<XrActionStatePose> ActionStateCommonPose;
// Convert action values to app / OSG friendly formats
template <typename T>
struct ActionTypeInfo;
// XrBool32 -> bool
template <>
struct ActionTypeInfo<XrActionStateBoolean>
{
static bool convert(XrBool32 value)
{
return value;
}
static bool defaultValue()
{
return false;
}
};
// float -> float
template <>
struct ActionTypeInfo<XrActionStateFloat>
{
static float convert(float value)
{
return value;
}
static float defaultValue()
{
return 0.0f;
}
};
// XrVector2f -> osg::Vec2f
template <>
struct ActionTypeInfo<XrActionStateVector2f>
{
static osg::Vec2f convert(const XrVector2f &value)
{
return osg::Vec2f(value.x, value.y);
}
static osg::Vec2f defaultValue()
{
return osg::Vec2f(0.0f, 0.0f);
}
};
/// Some action states have currentValue and related fields.
template <typename T>
class ActionStateSimple : public ActionStateCommon<T>
{
private:
typedef ActionStateCommon<T> Base;
public:
typedef ActionTypeInfo<T> Info;
// Constructors
ActionStateSimple(Action *action, Session *session,
Path subactionPath = Path()) :
Base(action, session, subactionPath)
{
}
// Accessors
auto getCurrentState() const
{
assert(this->valid());
return Info::convert(Base::_state.currentState);
}
bool hasChangedSinceLastSync() const
{
assert(this->valid());
return Base::_state.changedSinceLastSync;
}
XrTime getLastChangedTime() const
{
assert(this->valid());
return Base::_state.lastChangedTime;
}
};
// These are the simple action state classes
typedef ActionStateSimple<XrActionStateBoolean> ActionStateBoolean;
typedef ActionStateSimple<XrActionStateFloat> ActionStateFloat;
typedef ActionStateSimple<XrActionStateVector2f> ActionStateVector2f;
/// Specialise Action for a specific input type
template <XrActionType type, typename T>
class ActionTyped : public Action
{
public:
typedef T State;
ActionTyped(ActionSet *actionSet,
const std::string &name,
const std::string &localizedName) :
Action(actionSet, name, localizedName, type)
{
}
osg::ref_ptr<State> createState(Session *session,
Path subactionPath = Path())
{
return new State(this, session, subactionPath);
}
};
// So ActionStatePose etc can take ActionPose etc in constructor
class ActionStatePose;
class ActionStateVibration;
// These are the final typed action classes
typedef ActionTyped<XR_ACTION_TYPE_BOOLEAN_INPUT, ActionStateBoolean> ActionBoolean;
typedef ActionTyped<XR_ACTION_TYPE_FLOAT_INPUT, ActionStateFloat> ActionFloat;
typedef ActionTyped<XR_ACTION_TYPE_VECTOR2F_INPUT, ActionStateVector2f> ActionVector2f;
typedef ActionTyped<XR_ACTION_TYPE_POSE_INPUT, ActionStatePose> ActionPose;
typedef ActionTyped<XR_ACTION_TYPE_VIBRATION_OUTPUT, ActionStateVibration> ActionVibration;
/// Pose actions have their own way to get the pose
class ActionStatePose : public ActionStateCommon<XrActionStatePose>
{
private:
typedef ActionStateCommon<XrActionStatePose> Base;
public:
// Constructors
ActionStatePose(ActionPose *action, Session *session,
Path subactionPath = Path());
~ActionStatePose();
// Accessors
Space *getSpace()
{
return _space.get();
}
protected:
osg::ref_ptr<Space> _space;
};
class ActionStateVibration : public osg::Referenced
{
public:
// Constructors
ActionStateVibration(ActionVibration *action, Session *session,
Path subactionPath = Path());
// Error checking
inline bool check(XrResult result, const char *warnMsg) const
{
return _action->check(result, warnMsg);
}
// Haptic vibrations
bool applyHapticFeedback(int64_t duration_ns, float frequency,
float amplitude) const;
bool stopHapticFeedback() const;
protected:
// Member data
osg::ref_ptr<Action> _action;
osg::ref_ptr<Session> _session;
Path _subactionPath;
};
} // osgXR::OpenXR
} // osgXR
#endif