mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-16 14:46:17 +02:00
180 lines
6.8 KiB
C++
Executable file
180 lines
6.8 KiB
C++
Executable file
//
|
|
// UserInputMapper.h
|
|
// interface/src/ui
|
|
//
|
|
// Created by Sam Gateau on 4/27/15.
|
|
// Copyright 2015 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#ifndef hifi_UserInputMapper_h
|
|
#define hifi_UserInputMapper_h
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <RegisteredMetaTypes.h>
|
|
|
|
#include <unordered_set>
|
|
#include <functional>
|
|
#include <memory>
|
|
|
|
class UserInputMapper : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
typedef unsigned short uint16;
|
|
typedef unsigned int uint32;
|
|
|
|
enum class ChannelType {
|
|
UNKNOWN = 0,
|
|
BUTTON = 1,
|
|
AXIS,
|
|
JOINT,
|
|
};
|
|
|
|
// Input is the unique identifier to find a n input channel of a particular device
|
|
// Devices are responsible for registering to the UseInputMapper so their input channels can be sued and mapped
|
|
// to the Action channels
|
|
class Input {
|
|
public:
|
|
union {
|
|
struct {
|
|
uint16 _device; // Up to 64K possible devices
|
|
uint16 _channel : 14; // 2^14 possible channel per Device
|
|
uint16 _type : 2; // 2 bits to store the Type directly in the ID
|
|
};
|
|
uint32 _id = 0; // by default Input is 0 meaning invalid
|
|
};
|
|
|
|
bool isValid() const { return (_id != 0); }
|
|
|
|
uint16 getDevice() const { return _device; }
|
|
uint16 getChannel() const { return _channel; }
|
|
uint32 getID() const { return _id; }
|
|
|
|
ChannelType getType() const { return (ChannelType) _type; }
|
|
bool isButton() const { return getType() == ChannelType::BUTTON; }
|
|
bool isAxis() const { return getType() == ChannelType::AXIS; }
|
|
bool isJoint() const { return getType() == ChannelType::JOINT; }
|
|
|
|
// WORKAROUND: the explicit initializer here avoids a bug in GCC-4.8.2 (but not found in 4.9.2)
|
|
// where the default initializer (a C++-11ism) for the union data above is not applied.
|
|
explicit Input() : _id(0) {}
|
|
explicit Input(uint32 id) : _id(id) {}
|
|
explicit Input(uint16 device, uint16 channel, ChannelType type) : _device(device), _channel(channel), _type(uint16(type)) {}
|
|
Input(const Input& src) : _id(src._id) {}
|
|
Input& operator = (const Input& src) { _id = src._id; return (*this); }
|
|
bool operator < (const Input& src) const { return _id < src._id; }
|
|
};
|
|
|
|
// Modifiers are just button inputID
|
|
typedef std::vector< Input > Modifiers;
|
|
|
|
class JointValue {
|
|
public:
|
|
glm::vec3 translation{ 0.0f };
|
|
glm::quat rotation;
|
|
|
|
JointValue() {};
|
|
JointValue(const JointValue&) = default;
|
|
JointValue& operator = (const JointValue&) = default;
|
|
};
|
|
|
|
typedef std::function<bool (const Input& input, int timestamp)> ButtonGetter;
|
|
typedef std::function<float (const Input& input, int timestamp)> AxisGetter;
|
|
typedef std::function<JointValue (const Input& input, int timestamp)> JointGetter;
|
|
|
|
class DeviceProxy {
|
|
public:
|
|
DeviceProxy() {}
|
|
|
|
ButtonGetter getButton = [] (const Input& input, int timestamp) -> bool { return false; };
|
|
AxisGetter getAxis = [] (const Input& input, int timestamp) -> bool { return 0.0f; };
|
|
JointGetter getJoint = [] (const Input& input, int timestamp) -> JointValue { return JointValue(); };
|
|
|
|
typedef std::shared_ptr<DeviceProxy> Pointer;
|
|
};
|
|
// GetFreeDeviceID should be called before registering a device to use an ID not used by a different device.
|
|
uint16 getFreeDeviceID() { return _nextFreeDeviceID++; }
|
|
bool registerDevice(uint16 deviceID, const DeviceProxy::Pointer& device);
|
|
DeviceProxy::Pointer getDeviceProxy(const Input& input);
|
|
|
|
|
|
// Actions are the output channels of the Mapper, that's what the InputChannel map to
|
|
// For now the Actions are hardcoded, this is bad, but we will fix that in the near future
|
|
enum Action {
|
|
LONGITUDINAL_BACKWARD = 0,
|
|
LONGITUDINAL_FORWARD,
|
|
|
|
LATERAL_LEFT,
|
|
LATERAL_RIGHT,
|
|
|
|
VERTICAL_DOWN,
|
|
VERTICAL_UP,
|
|
|
|
YAW_LEFT,
|
|
YAW_RIGHT,
|
|
|
|
PITCH_DOWN,
|
|
PITCH_UP,
|
|
|
|
BOOM_IN,
|
|
BOOM_OUT,
|
|
|
|
NUM_ACTIONS,
|
|
};
|
|
|
|
float getActionState(Action action) const { return _actionStates[action]; }
|
|
void assignDefaulActionScales();
|
|
|
|
// Add input channel to the mapper and check that all the used channels are registered.
|
|
// Return true if theinput channel is created correctly, false either
|
|
bool addInputChannel(Action action, const Input& input, float scale = 1.0f);
|
|
bool addInputChannel(Action action, const Input& input, const Input& modifer, float scale = 1.0f);
|
|
|
|
// Under the hood, the input channels are organized in map sorted on the _output
|
|
// The InputChannel class is just the full values describing the input channel in one object
|
|
class InputChannel {
|
|
public:
|
|
Input _input;
|
|
Input _modifier = Input(); // make it invalid by default, meaning no modifier
|
|
Action _action = LONGITUDINAL_BACKWARD;
|
|
float _scale = 0.0f;
|
|
|
|
InputChannel() {}
|
|
InputChannel(const Input& input, const Input& modifier, Action action, float scale = 1.0f) :
|
|
_input(input), _modifier(modifier), _action(action), _scale(scale) {}
|
|
InputChannel(const InputChannel& src) : InputChannel(src._input, src._modifier, src._action, src._scale) {}
|
|
InputChannel& operator = (const InputChannel& src) { _input = src._input; _modifier = src._modifier; _action = src._action; _scale = src._scale; return (*this); }
|
|
|
|
bool hasModifier() { return _modifier.isValid(); }
|
|
};
|
|
typedef std::vector< InputChannel > InputChannels;
|
|
|
|
// Add a bunch of input channels, return the true number of channels that successfully were added
|
|
int addInputChannels(const InputChannels& channels);
|
|
//Grab all the input channels currently in use, return the number
|
|
int getInputChannels(InputChannels& channels) const;
|
|
|
|
// Update means go grab all the device input channels and update the output channel values
|
|
void update(float deltaTime);
|
|
|
|
// Default contruct allocate the poutput size with the current hardcoded action channels
|
|
UserInputMapper() { assignDefaulActionScales(); }
|
|
|
|
protected:
|
|
typedef std::map<int, DeviceProxy::Pointer> DevicesMap;
|
|
DevicesMap _registeredDevices;
|
|
uint16 _nextFreeDeviceID = 1;
|
|
|
|
typedef std::map<int, Modifiers> InputToMoModifiersMap;
|
|
InputToMoModifiersMap _inputToModifiersMap;
|
|
|
|
typedef std::multimap<Action, InputChannel> ActionToInputsMap;
|
|
ActionToInputsMap _actionToInputsMap;
|
|
|
|
std::vector<float> _actionStates = std::vector<float>(NUM_ACTIONS, 0.0f);
|
|
std::vector<float> _actionScales = std::vector<float>(NUM_ACTIONS, 1.0f);
|
|
};
|
|
|
|
#endif // hifi_UserInputMapper_h
|