Initial setup of input stuff

This commit is contained in:
Kae 2023-07-02 06:34:43 +10:00
parent 2c43b50531
commit 15b0e99460
9 changed files with 225 additions and 3 deletions

View File

@ -9,13 +9,11 @@ SET (star_application_HEADERS
StarApplication.hpp StarApplication.hpp
StarApplicationController.hpp StarApplicationController.hpp
StarMainApplication.hpp StarMainApplication.hpp
StarInputEvent.hpp
StarRenderer.hpp StarRenderer.hpp
) )
SET (star_application_SOURCES SET (star_application_SOURCES
StarApplication.cpp StarApplication.cpp
StarInputEvent.cpp
StarRenderer.cpp StarRenderer.cpp
) )

View File

@ -167,7 +167,7 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
m_mainMixer->setVolume(0.5); m_mainMixer->setVolume(0.5);
m_guiContext = make_shared<GuiContext>(m_mainMixer->mixer(), appController); m_guiContext = make_shared<GuiContext>(m_mainMixer->mixer(), appController);
m_input = make_shared<Input>();
auto configuration = m_root->configuration(); auto configuration = m_root->configuration();
bool vsync = configuration->get("vsync").toBool(); bool vsync = configuration->get("vsync").toBool();

View File

@ -11,6 +11,7 @@
#include "StarErrorScreen.hpp" #include "StarErrorScreen.hpp"
#include "StarCinematic.hpp" #include "StarCinematic.hpp"
#include "StarKeyBindings.hpp" #include "StarKeyBindings.hpp"
#include "StarInput.hpp"
#include "StarMainApplication.hpp" #include "StarMainApplication.hpp"
namespace Star { namespace Star {
@ -74,6 +75,7 @@ private:
// Valid after applicationInit is called // Valid after applicationInit is called
MainMixerPtr m_mainMixer; MainMixerPtr m_mainMixer;
GuiContextPtr m_guiContext; GuiContextPtr m_guiContext;
InputPtr m_input;
// Valid after renderInit is called the first time // Valid after renderInit is called the first time
CinematicPtr m_cinematicOverlay; CinematicPtr m_cinematicOverlay;

View File

@ -40,6 +40,7 @@ SET (star_core_HEADERS
StarIdMap.hpp StarIdMap.hpp
StarImage.hpp StarImage.hpp
StarImageProcessing.hpp StarImageProcessing.hpp
StarInputEvent.hpp
StarInterpolation.hpp StarInterpolation.hpp
StarRefPtr.hpp StarRefPtr.hpp
StarIterator.hpp StarIterator.hpp
@ -142,6 +143,7 @@ SET (star_core_SOURCES
StarIODevice.cpp StarIODevice.cpp
StarImage.cpp StarImage.cpp
StarImageProcessing.cpp StarImageProcessing.cpp
StarInputEvent.cpp
StarJson.cpp StarJson.cpp
StarJsonBuilder.cpp StarJsonBuilder.cpp
StarJsonExtra.cpp StarJsonExtra.cpp

View File

@ -56,6 +56,7 @@ SET (star_game_HEADERS
StarGameTypes.hpp StarGameTypes.hpp
StarHumanoid.hpp StarHumanoid.hpp
StarImageMetadataDatabase.hpp StarImageMetadataDatabase.hpp
StarInput.hpp
StarInteractionTypes.hpp StarInteractionTypes.hpp
StarInterpolationTracker.hpp StarInterpolationTracker.hpp
StarInventoryTypes.hpp StarInventoryTypes.hpp
@ -314,6 +315,7 @@ SET (star_game_SOURCES
StarGameTypes.cpp StarGameTypes.cpp
StarHumanoid.cpp StarHumanoid.cpp
StarImageMetadataDatabase.cpp StarImageMetadataDatabase.cpp
StarInput.cpp
StarInteractionTypes.cpp StarInteractionTypes.cpp
StarInterpolationTracker.cpp StarInterpolationTracker.cpp
StarInventoryTypes.cpp StarInventoryTypes.cpp

58
source/game/StarInput.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "StarInput.hpp"
#include "StarAssets.hpp"
#include "StarRoot.hpp"
namespace Star {
size_t hash<InputVariant>::operator()(InputVariant const& v) const {
size_t indexHash = hashOf(v.typeIndex());
if (auto key = v.ptr<Key>())
hashCombine(indexHash, hashOf(*key));
else if (auto mButton = v.ptr<MouseButton>())
hashCombine(indexHash, hashOf(*mButton));
else if (auto cButton = v.ptr<ControllerButton>())
hashCombine(indexHash, hashOf(*cButton));
return indexHash;
}
Input* Input::s_singleton;
Input* Input::singletonPtr() {
return s_singleton;
}
Input& Input::singleton() {
if (!s_singleton)
throw InputException("Input::singleton() called with no Input instance available");
else
return *s_singleton;
}
Input::Input() {
if (s_singleton)
throw InputException("Singleton Input has been constructed twice");
s_singleton = this;
}
Input::~Input() {
s_singleton = nullptr;
}
void Input::reset() {
}
void Input::reload() {
reset();
auto assets = Root::singleton().assets();
for (auto& bindPath : assets->scanExtension("binds")) {
Json config = assets->json(bindPath);
}
}
}

160
source/game/StarInput.hpp Normal file
View File

@ -0,0 +1,160 @@
#ifndef STAR_INPUT_HPP
#define STAR_INPUT_HPP
#include "StarInputEvent.hpp"
#include "StarJson.hpp"
#include "StarListener.hpp"
#include "StarHash.hpp"
namespace Star {
STAR_CLASS(Input);
STAR_EXCEPTION(InputException, StarException);
typedef Variant<Key, MouseButton, ControllerButton> InputVariant;
template <>
struct hash<InputVariant> {
size_t operator()(InputVariant const& v) const;
};
class Input {
public:
struct NoBind {
String error;
NoBind(String err);
};
struct KeyBind {
Key key = Key::Zero;
KeyMod mods = KeyMod::NoMod;
uint8_t priority = 0;
inline bool operator<(KeyBind const& rhs) const {
return priority < rhs.priority;
}
inline bool operator>(KeyBind const& rhs) const {
return priority > rhs.priority;
}
};
struct MouseBind {
MouseButton button = MouseButton::Left;
KeyMod mods = KeyMod::NoMod;
uint8_t priority = 0;
};
struct ControllerBind {
unsigned int controller = 0;
ControllerButton button = ControllerButton::Invalid;
};
typedef Variant<NoBind, KeyBind, MouseBind, ControllerBind> Bind;
static Bind bindFromJson(Json const& json);
static Json bindToJson(Bind const& bind);
struct Category;
struct BindEntry {
// The internal ID of this entry.
String id;
// The category this entry belongs to.
String category;
// The user-facing name of this entry.
String name;
// The default binds.
List<Bind> defaultBinds;
// The user-configured binds.
List<Bind> customBinds;
BindEntry(Json const& config, Category const& category);
};
struct BindRef {
KeyMod mods;
uint8_t priority;
// Invalidated on reload, careful!
BindEntry* entry;
};
struct BindRefSorter {
inline bool operator() (BindRef const& a, BindRef const& b) {
return a.priority > b.priority;
}
};
struct BindCategory {
String id;
String name;
Json meta;
StringMap<BindEntry> entries;
BindCategory(Json const& data);
};
struct InputState {
size_t presses = 0;
size_t releases = 0;
// Calls the passed functions for each press and release.
template <typename PressFunction, typename ReleaseFunction>
void forEach(PressFunction&& pressed, ReleaseFunction&& released) {
for (size_t i = 0; i != releases; ++i) {
pressed();
released();
}
}
constexpr bool held() {
return presses < releases;
}
};
// Get pointer to the singleton root instance, if it exists. Otherwise,
// returns nullptr.
static Input* singletonPtr();
// Gets reference to GuiContext singleton, throws GuiContextException if root
// is not initialized.
static Input& singleton();
Input();
~Input();
Input(Input const&) = delete;
Input& operator=(Input const&) = delete;
// Clears input state. Should be done at the end of the client loop.
void reset();
// Handles an input event.
bool handleInput(InputEvent const& event);
// Loads input categories and their binds from Assets.
void reload();
private:
static Input* s_singleton;
// Regenerated on reload.
StringMap<BindCategory> m_bindCategories;
// Contains raw pointers to bind entries in categories, so also regenerated on reload.
HashMap<InputVariant, List<BindRef>> m_inputsToBinds;
ListenerPtr m_rootReloadListener;
// Per-frame input state maps.
//Raw input state
HashMap<InputVariant, InputState> m_inputStates;
//Bind input state
HashMap<BindEntry*, InputState> m_bindStates;
};
}
#endif