// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "InputDevice.h"
#include "Engine/Core/Types/Guid.h"
#include "Engine/Core/Math/Vector2.h"
///
/// General identifiers for potential force feedback channels. These will be mapped according to the platform specific implementation.
///
API_STRUCT() struct FLAXENGINE_API GamepadVibrationState
{
DECLARE_SCRIPTING_TYPE_MINIMAL(GamepadVibrationState);
///
/// The left large motor vibration.
///
API_FIELD() float LeftLarge;
///
/// The left small motor vibration.
///
API_FIELD() float LeftSmall;
///
/// The right large motor vibration.
///
API_FIELD() float RightLarge;
///
/// The right small motor vibration.
///
API_FIELD() float RightSmall;
GamepadVibrationState()
: LeftLarge(0.0f)
, LeftSmall(0.0f)
, RightLarge(0.0f)
, RightSmall(0.0f)
{
}
};
///
/// Gamepad buttons and axis mapping description.
/// Allows converting input from the different gamepads into a universal format (see and ).
///
struct FLAXENGINE_API GamepadLayout
{
///
/// The buttons mapping. Index by gamepad button id from 0 to 31 (see ).
///
GamepadButton Buttons[(int32)GamepadButton::MAX];
///
/// The axis mapping. Index by gamepad axis id from 0 to 5 (see ).
///
GamepadAxis Axis[(int32)GamepadAxis::MAX];
///
/// The axis ranges mapping (X is scale, Y is offset. Eg. mappedVal = X * value + Y). It allows to invert any axis or map axis range.
///
Float2 AxisMap[(int32)GamepadAxis::MAX];
///
/// Initializes layout with default values.
///
void Init();
};
///
/// Represents a single hardware gamepad device. Used by the Input to report raw gamepad input events.
///
API_CLASS(NoSpawn, Sealed) class FLAXENGINE_API Gamepad : public InputDevice
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Gamepad);
public:
///
/// The universal gamepad state description. All hardware gamepad device handlers should map input to match this structure.
/// Later on, each gamepad may use individual layout for a game.
///
struct State
{
///
/// The buttons state (pressed if true).
///
bool Buttons[(int32)GamepadButton::MAX];
///
/// The axis state (normalized value).
///
float Axis[(int32)GamepadAxis::MAX];
///
/// Clears the state.
///
void Clear()
{
Platform::MemoryClear(this, sizeof(State));
}
};
protected:
Guid _productId;
State _state;
State _mappedState;
State _mappedPrevState;
explicit Gamepad(const Guid& productId, const String& name);
public:
///
/// The gamepad layout.
///
GamepadLayout Layout;
public:
///
/// Gets the gamepad device type identifier.
///
/// The id.
API_PROPERTY() FORCE_INLINE const Guid& GetProductID() const
{
return _productId;
}
///
/// Gets the current gamepad state.
///
/// The result.
FORCE_INLINE void GetState(State& result) const
{
result = _state;
}
///
/// Gets the gamepad axis value.
///
/// Gamepad axis to check
/// Axis value.
API_FUNCTION() FORCE_INLINE float GetAxis(const GamepadAxis axis) const
{
return _mappedState.Axis[static_cast(axis)];
}
///
/// Gets the gamepad button state (true if being pressed during the current frame).
///
/// Gamepad button to check
/// True if user holds down the button, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetButton(const GamepadButton button) const
{
return _mappedState.Buttons[static_cast(button)];
}
///
/// Gets the gamepad button down state (true if was pressed during the current frame).
///
/// Gamepad button to check
/// True if user starts pressing down the button, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetButtonDown(const GamepadButton button) const
{
return _mappedState.Buttons[static_cast(button)] && !_mappedPrevState.Buttons[static_cast(button)];
}
///
/// Checks if any gamepad button is currently pressed.
///
API_PROPERTY() bool IsAnyButtonDown() const;
///
/// Gets the gamepad button up state (true if was released during the current frame).
///
/// Gamepad button to check
/// True if user releases the button, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetButtonUp(const GamepadButton button) const
{
return !_mappedState.Buttons[static_cast(button)] && _mappedPrevState.Buttons[static_cast(button)];
}
public:
///
/// Sets the state of the gamepad vibration. Ignored if controller does not support this.
///
/// The state.
API_FUNCTION() virtual void SetVibration(const GamepadVibrationState& state)
{
}
///
/// Sets the color of the gamepad light. Ignored if controller does not support this.
///
/// The color.
API_FUNCTION() virtual void SetColor(const Color& color)
{
}
///
/// Resets the color of the gamepad light to the default. Ignored if controller does not support this.
///
API_FUNCTION() virtual void ResetColor()
{
}
public:
// [InputDevice]
void ResetState() override;
bool Update(EventQueue& queue) final override;
};