summaryrefslogtreecommitdiff
path: root/src/player-input.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-11-15 13:03:48 -0500
committerJonathan Bradley <jcb@pikum.xyz>2023-11-15 13:03:48 -0500
commit1513216876a0409f45d88cbad14ae8b48fca37e2 (patch)
tree32b48d966faf36138dd985e4df739a83cddc5f48 /src/player-input.cpp
parent6a30d21c5175c27aeccc8a6ae956c274f3ef9621 (diff)
major input refactor and add debug camera
Diffstat (limited to 'src/player-input.cpp')
-rw-r--r--src/player-input.cpp762
1 files changed, 633 insertions, 129 deletions
diff --git a/src/player-input.cpp b/src/player-input.cpp
index 4b2b6be..9f50307 100644
--- a/src/player-input.cpp
+++ b/src/player-input.cpp
@@ -1,9 +1,38 @@
#include "player-input.hpp"
-#include "window.hpp"
+
+#include "dynamic-array.hpp"
#include "game-settings.hpp"
+#include "window.hpp"
+
+#include <GLFW/glfw3.h>
#include <chrono>
+struct CursorEnterEvent {
+ bool entered;
+};
+struct CursorPosEvent {
+ double x;
+ double y;
+};
+struct KeyEvent {
+ int32_t button;
+ int32_t mods;
+ int8_t action;
+};
+struct MouseButtonEvent {
+ int32_t button;
+ int32_t mods;
+ int8_t action;
+};
+struct ScrollEvent {
+ double x;
+ double y;
+};
+struct WindowFocusEvent {
+ bool focused;
+};
+
GLFWcursorenterfun prevCursorEnterCallback;
GLFWcursorposfun prevCursorPosCallback;
GLFWkeyfun prevKeyCallback;
@@ -11,166 +40,500 @@ GLFWmousebuttonfun prevMouseButtonCallback;
GLFWscrollfun prevScrollCallback;
GLFWwindowfocusfun prevWindowFocusCallback;
-TypeSafeInt_B(InputEventHash);
-TypeSafeInt_B(InputEventType);
-TypeSafeInt_B(InputCursorEntered);
-TypeSafeInt_B(InputKeyboardKeyAction);
-TypeSafeInt_B(InputMouseButtonAction);
-TypeSafeInt_B(InputWindowFocused);
-
-DynArray<PkeInputEvent> UnhandledPkeInputEvents{0, nullptr};
-
-bool PkeInput_Query(const PkeInputEvent &mask) {
- auto count = UnhandledPkeInputEvents.Count();
- for (long i = 0; i < count; ++i) {
- const auto &ev = UnhandledPkeInputEvents[i];
- // TODO this could probably be reduced to a single & op
- // - if we exclude x, y, button, scanCode, and mods
- // there are less than 64 options total
- if (!(mask.type == ev.type)) continue;
- if (!(mask.tickCount == ev.tickCount)) continue;
- if (!(mask.cursorEntered == ev.cursorEntered)) continue;
- if (!(mask.keyboardKeyAction == ev.keyboardKeyAction)) continue;
- if (!(mask.mouseButtonAction == ev.mouseButtonAction)) continue;
- if (!(mask.windowFocused == ev.windowFocused)) continue;
- if (!(mask.x == ev.x)) continue;
- if (!(mask.y == ev.y)) continue;
- if (!(mask.button == ev.button)) continue;
- if (!(mask.scanCode == ev.scanCode)) continue;
- if (!(mask.mods == ev.mods)) continue;
- UnhandledPkeInputEvents.Remove(i);
- return true;
- }
- return false;
+TypeSafeInt_B(InputActionSetHandle);
+
+DynArray<CursorPosEvent> unhandledCursorPosEvents{512, nullptr};
+DynArray<CursorEnterEvent> unhandledCursorEnterEvents{8, nullptr};
+DynArray<KeyEvent> unhandledKeyEvents{8, nullptr};
+DynArray<MouseButtonEvent> unhandledMouseButtonEvents{8, nullptr};
+DynArray<ScrollEvent> unhandledScrollEvents{8, nullptr};
+DynArray<WindowFocusEvent> unhandledWindowFocusEvents{8, nullptr};
+
+DynArray<PkeCursorEnterEvent> registeredCursorEnterEvents{8, nullptr};
+bool lastCursorEntered = false;
+DynArray<PkeCursorPosEvent> registeredCursorPosEvents{8, nullptr};
+struct {
+ double x = 0;
+ double y = 0;
+} lastMousePos;
+DynArray<PkeKeyEvent> registeredKeyEvents{8, nullptr};
+DynArray<PkeMouseButtonEvent> registeredMouseButtonEvents{8, nullptr};
+DynArray<PkeScrollEvent> registeredScrollEvents{8, nullptr};
+DynArray<PkeWindowFocusEvent> registeredWindowFocusEvents{8, nullptr};
+bool lastWindowFocus = false;
+
+// DynArray<PkeInputEvent> UnhandledPkeInputEvents{1024, nullptr};
+
+DynArray<PkeInputSet> registeredInputSets{0, nullptr};
+DynArray<InputActionSetHandle> activeInputSetStack{0, nullptr};
+
+PkeInputAction *FindActionByName(const char *actionName) {
+ int64_t count = 0;
+ count = activeInputSetStack.Count();
+ for (int64_t i = count - 1; i >= 0; --i) {
+ InputActionSetHandle handle = activeInputSetStack[i];
+ InputActionSetHandle_T index = static_cast<InputActionSetHandle_T>(handle);
+ PkeInputSet &set = registeredInputSets[index];
+ for (int64_t k = 0; k < set.actionCount; ++k) {
+ PkeInputAction &inputAction = set.actions[k];
+ if (strcmp(actionName, inputAction.name) != 0) {
+ continue;
+ };
+ return &inputAction;
+ }
+ }
+ return nullptr;
+}
+template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByAction(const PkeInputAction *inputAction, S *&activeEvent) {
+ activeEvent = nullptr;
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ activeEvent = &registeredCursorEnterEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ activeEvent = &registeredCursorPosEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ activeEvent = &registeredKeyEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_KEY;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ activeEvent = &registeredMouseButtonEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ activeEvent = &registeredScrollEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_SCROLL;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ activeEvent = &registeredWindowFocusEvents[inputAction->eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS;
+ }
+ return InputEventHash{0};
}
+template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByName(const char *actionName, S *&activeEvent) {
+ activeEvent = nullptr;
+ bool any = false;
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ any = any || bool(registeredCursorEnterEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ any = any || bool(registeredCursorPosEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ any = any || bool(registeredKeyEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ any = any || bool(registeredMouseButtonEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ any = any || bool(registeredScrollEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ any = any || bool(registeredWindowFocusEvents.Count());
+ }
+ if (any == false) return InputEventHash{0};
+ int64_t count = 0;
+ count = activeInputSetStack.Count();
+ for (int64_t i = count - 1; i >= 0; --i) {
+ InputActionSetHandle handle = activeInputSetStack[i];
+ InputActionSetHandle_T index = static_cast<InputActionSetHandle_T>(handle);
+ PkeInputSet &set = registeredInputSets[index];
+ for (int64_t k = 0; k < set.actionCount; ++k) {
+ PkeInputAction &inputAction = set.actions[k];
+ if (strcmp(actionName, inputAction.name) != 0) {
+ continue;
+ };
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ activeEvent = &registeredCursorEnterEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ activeEvent = &registeredCursorPosEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ activeEvent = &registeredKeyEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_KEY;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ activeEvent = &registeredMouseButtonEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ activeEvent = &registeredScrollEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_SCROLL;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ activeEvent = &registeredWindowFocusEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS;
+ }
+ }
+ }
+ return InputEventHash{0};
+}
+template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByType(const PkeInputEventMask &mask, S *&activeEvent) {
+ activeEvent = nullptr;
+ bool any = false;
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ any = any || bool(registeredCursorEnterEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ any = any || bool(registeredCursorPosEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ any = any || bool(registeredKeyEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ any = any || bool(registeredMouseButtonEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ any = any || bool(registeredScrollEvents.Count());
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ any = any || bool(registeredWindowFocusEvents.Count());
+ }
+ if (any == false) return InputEventHash{0};
+ int64_t count = 0;
+ count = activeInputSetStack.Count();
+ for (int64_t i = count - 1; i >= 0; --i) {
+ InputActionSetHandle handle = activeInputSetStack[i];
+ InputActionSetHandle_T index = static_cast<InputActionSetHandle_T>(handle);
+ PkeInputSet &set = registeredInputSets[index];
+ for (int64_t k = 0; k < set.actionCount; ++k) {
+ PkeInputAction &inputAction = set.actions[k];
+ for (int64_t l = 0; l < PKE_INPUT_ACTION_MASK_COUNT; ++l) {
+ PkeInputEventMask &evMask = inputAction.masks[l];
+ if ((evMask.computedHash & mask.computedHash) == InputEventHash{0}) {
+ continue;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ if (evMask.button != mask.button) {
+ continue;
+ }
+ if (evMask.mods != mask.mods) {
+ continue;
+ }
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ if (evMask.button != mask.button) {
+ continue;
+ }
+ if (evMask.mods != mask.mods) {
+ continue;
+ }
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ activeEvent = &registeredCursorEnterEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ activeEvent = &registeredCursorPosEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ activeEvent = &registeredKeyEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_KEY;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ activeEvent = &registeredMouseButtonEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ activeEvent = &registeredScrollEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_SCROLL;
+ }
+ if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ activeEvent = &registeredWindowFocusEvents[inputAction.eventIndex];
+ return PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS;
+ }
+ }
+ }
+ }
+ return InputEventHash{0};
+}
+constexpr auto FindActivePkeInputAction_CursorEnter_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER, PkeCursorEnterEvent>;
+constexpr auto FindActivePkeInputAction_CursorPos_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, PkeCursorPosEvent>;
+constexpr auto FindActivePkeInputAction_Key_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_KEY, PkeKeyEvent>;
+constexpr auto FindActivePkeInputAction_MouseButton_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON, PkeMouseButtonEvent>;
+constexpr auto FindActivePkeInputAction_Scroll_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_SCROLL, PkeScrollEvent>;
+constexpr auto FindActivePkeInputAction_WindowFocus_ByType = FindActivePkeInputAction_ByType<PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS, PkeWindowFocusEvent>;
+
+constexpr auto FindActivePkeInputAction_CursorEnter_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER, PkeCursorEnterEvent>;
+constexpr auto FindActivePkeInputAction_CursorPos_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, PkeCursorPosEvent>;
+constexpr auto FindActivePkeInputAction_Key_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_KEY, PkeKeyEvent>;
+constexpr auto FindActivePkeInputAction_MouseButton_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON, PkeMouseButtonEvent>;
+constexpr auto FindActivePkeInputAction_Scroll_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_SCROLL, PkeScrollEvent>;
+constexpr auto FindActivePkeInputAction_WindowFocus_ByName = FindActivePkeInputAction_ByName<PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS, PkeWindowFocusEvent>;
+
void PkeInput_Tick(double delta) {
- // If we haven't handled an event within two seconds, we probably don't need it
- static GameTimeDuration eventExpiration(std::chrono::seconds(2));
- int64_t removeCount = 0;
- int64_t unhandledCount = UnhandledPkeInputEvents.Count();
- auto expiredTime = pkeSettings.steadyClock.now() - eventExpiration;
- for (int64_t i = 0; i < unhandledCount; ++i) {
- auto &ev = UnhandledPkeInputEvents[i];
- ev.tickCount += 1;
- if (ev.timePoint < expiredTime) {
- removeCount += 1;
+ // reset everything
+ // @performance could happen concurrently
+ {
+ int64_t count = 0;
+ count = registeredCursorPosEvents.Count();
+ for (int64_t i = 0; i < count; ++i) {
+ auto &ev = registeredCursorPosEvents[i];
+ ev.xMotion = 0;
+ ev.yMotion = 0;
+ }
+ count = registeredKeyEvents.Count();
+ for (int64_t i = 0; i < count; ++i) {
+ auto &ev = registeredKeyEvents[i];
+ // TODO the idea here was right, but wrong place and too wide a swath
+ // if (i < count - 1) ev.isPressed = false;
+ ev.pressCount = 0;
+ }
+ count = registeredMouseButtonEvents.Count();
+ for (int64_t i = 0; i < count; ++i) {
+ auto &ev = registeredMouseButtonEvents[i];
+ // TODO the idea here was right, but wrong place and too wide a swath
+ // if (i < count - 1) ev.isPressed = false;
+ ev.pressCount = 0;
+ }
+ count = registeredScrollEvents.Count();
+ for (int64_t i = 0; i < count; ++i) {
+ auto &ev = registeredScrollEvents[i];
+ ev.xMotion = 0;
+ ev.yMotion = 0;
+ }
+ }
+
+ // handle unhandled events
+ // @performance cache action->event results
+ {
+ do { // while (0)
+ PkeCursorEnterEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_CursorEnter_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_CURSOR_ENTER_EVENTS
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ break;
+ }
+ const auto &ev = unhandledCursorEnterEvents[unhandledCursorEnterEvents.Count() - 1];
+ primaryEvent->isEntered = ev.entered;
+ lastCursorEntered = ev.entered;
+ } while (0);
+ do { // while (0)
+ PkeCursorPosEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_CursorPos_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_CURSOR_POS_EVENTS
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ break;
+ }
+ int64_t count = unhandledCursorPosEvents.Count();
+ for (long i = 0; i < count; ++i) {
+ const auto &ev = unhandledCursorPosEvents[i];
+ primaryEvent->xMotion += ev.x - lastMousePos.x;
+ primaryEvent->yMotion += ev.y - lastMousePos.y;
+ lastMousePos.x = ev.x;
+ lastMousePos.y = ev.y;
+ }
+ } while (0);
+ do { // while (0)
+ int64_t count = unhandledKeyEvents.Count();
+ for (long i = 0; i < count; ++i) {
+ const auto &ev = unhandledKeyEvents[i];
+ PkeKeyEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_Key_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS,
+ .button = ev.button,
+ .mods = ev.mods,
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ continue;
+ }
+ if (ev.action == GLFW_PRESS) {
+ primaryEvent->isPressed = true;
+ } else if (ev.action == GLFW_RELEASE) {
+ if (primaryEvent->isPressed == true) {
+ primaryEvent->pressCount += 1;
+ }
+ primaryEvent->isPressed = false;
+ } else {
+ // repeat
+ primaryEvent->isPressed = true;
+ primaryEvent->pressCount += 1;
+ }
+ }
+ } while (0);
+ do { // while (0)
+ int64_t count = unhandledMouseButtonEvents.Count();
+ for (long i = 0; i < count; ++i) {
+ const auto &ev = unhandledMouseButtonEvents[i];
+ PkeMouseButtonEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_MouseButton_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS,
+ .button = ev.button,
+ .mods = ev.mods,
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ continue;
+ }
+ if (ev.action == GLFW_PRESS) {
+ primaryEvent->isPressed = true;
+ } else if (ev.action == GLFW_RELEASE) {
+ if (primaryEvent->isPressed == true) {
+ primaryEvent->pressCount += 1;
+ }
+ primaryEvent->isPressed = false;
+ }
+ }
+ } while (0);
+ do { // while (0)
+ PkeScrollEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_Scroll_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_SCROLL_EVENTS
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ break;
+ }
+ int64_t count = unhandledScrollEvents.Count();
+ for (long i = 0; i < count; ++i) {
+ const auto &ev = unhandledScrollEvents[i];
+ primaryEvent->xMotion += ev.x;
+ primaryEvent->yMotion += ev.y;
+ }
+ } while (0);
+ do { // while (0)
+ PkeWindowFocusEvent *primaryEvent = nullptr;
+ FindActivePkeInputAction_WindowFocus_ByType(PkeInputEventMask {
+ .computedHash = PKE_INPUT_HASH_ALL_WINDOW_FOCUS_EVENTS
+ }, primaryEvent);
+ if (primaryEvent == nullptr) {
+ break;
+ }
+ const auto &ev = unhandledWindowFocusEvents[unhandledWindowFocusEvents.Count() - 1];
+ primaryEvent->isFocused = ev.focused;
+ lastWindowFocus = ev.focused;
+ } while (0);
+ }
+ unhandledCursorEnterEvents.Resize(0);
+ unhandledCursorPosEvents.Resize(0);
+ unhandledKeyEvents.Resize(0);
+ unhandledMouseButtonEvents.Resize(0);
+ unhandledScrollEvents.Resize(0);
+ unhandledWindowFocusEvents.Resize(0);
+
+ // set boolean events with latest data
+ // - we do this after processing events to make sure that if a set is
+ // unregistered, the appropriate values are propagated
+ // - theoretically this scenario could be handled on unregister,
+ // but I'm not sure which would be more performant
+ {
+ int64_t count = 0;
+ count = registeredCursorEnterEvents.Count();
+ for (int64_t i = 0; i < count - 1; ++i) {
+ auto &ev = registeredCursorEnterEvents[i];
+ ev.isEntered = lastCursorEntered;
+ }
+ count = registeredWindowFocusEvents.Count();
+ for (int64_t i = 0; i < count - 1; ++i) {
+ auto &ev = registeredWindowFocusEvents[i];
+ ev.isFocused = lastWindowFocus;
}
}
- if (removeCount > 0) {
- UnhandledPkeInputEvents.Remove(0, removeCount);
+}
+
+PkeInputEventHolder PkeInput_Query(const char *actionName) {
+ PkeInputEventBase *ev = nullptr;
+ auto *action = FindActionByName(actionName);
+ InputEventHash type = InputEventHash{0};
+ if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER)) {
+ PkeCursorEnterEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER, PkeCursorEnterEvent>(action, event);
+ ev = event;
+ } else if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS)) {
+ PkeCursorPosEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, PkeCursorPosEvent>(action, event);
+ ev = event;
+ } else if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY)) {
+ PkeKeyEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_KEY, PkeKeyEvent>(action, event);
+ ev = event;
+ } else if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON)) {
+ PkeMouseButtonEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON, PkeMouseButtonEvent>(action, event);
+ ev = event;
+ } else if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL)) {
+ PkeScrollEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_SCROLL, PkeScrollEvent>(action, event);
+ ev = event;
+ } else if (bool(action->primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS)) {
+ PkeWindowFocusEvent *event;
+ type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS, PkeWindowFocusEvent>(action, event);
+ ev = event;
}
+ return PkeInputEventHolder {
+ .type = type,
+ .ptr = ev,
+ };
}
void CursorEnterCallback(GLFWwindow *window, int entered) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_CURSOR_ENTER;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = InputCursorEntered{static_cast<InputCursorEntered_T>(entered)};
- ev.keyboardKeyAction = PKE_INPUT_KEYBOARD_KEY_ACTION_UNSET;
- ev.mouseButtonAction = PKE_INPUT_MOUSE_BUTTON_ACTION_UNSET;
- ev.windowFocused = PKE_INPUT_WINDOW_FOCUSED_UNSET;
- ev.x = 0;
- ev.y = 0;
- ev.button = 0;
- ev.scanCode = 0;
- ev.mods = 0;
- ev.tickCount = 0;
+ if (registeredCursorEnterEvents.Count()) {
+ auto &ev = unhandledCursorEnterEvents.Push();
+ ev.entered = bool(entered);
+ }
if (prevCursorEnterCallback) {
prevCursorEnterCallback(window, entered);
}
}
void CursorPosCallback(GLFWwindow *window, double xPos, double yPos) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_CURSOR_POS;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = PKE_INPUT_CURSOR_ENTERED_UNSET;
- ev.keyboardKeyAction = PKE_INPUT_KEYBOARD_KEY_ACTION_UNSET;
- ev.mouseButtonAction = PKE_INPUT_MOUSE_BUTTON_ACTION_UNSET;
- ev.windowFocused = PKE_INPUT_WINDOW_FOCUSED_UNSET;
- ev.x = xPos;
- ev.y = yPos;
- ev.button = 0;
- ev.scanCode = 0;
- ev.mods = 0;
- ev.tickCount = 0;
+ if (registeredCursorPosEvents.Count()) {
+ auto &ev = unhandledCursorPosEvents.Push();
+ ev.x = xPos;
+ ev.y = yPos;
+ }
if (prevCursorPosCallback) {
prevCursorPosCallback(window, xPos, yPos);
}
}
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_KEY;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = PKE_INPUT_CURSOR_ENTERED_UNSET;
- ev.keyboardKeyAction = InputKeyboardKeyAction{static_cast<InputKeyboardKeyAction_T>(action)};
- ev.mouseButtonAction = PKE_INPUT_MOUSE_BUTTON_ACTION_UNSET;
- ev.windowFocused = PKE_INPUT_WINDOW_FOCUSED_UNSET;
- ev.x = 0;
- ev.y = 0;
- ev.button = key;
- ev.scanCode = scancode;
- ev.mods = mods;
- ev.tickCount = 0;
+ if (registeredKeyEvents.Count()) {
+ auto &ev = unhandledKeyEvents.Push();
+ ev.button = key;
+ ev.mods = mods & 0x0F;
+ ev.action = action;
+ }
if (prevKeyCallback) {
prevKeyCallback(window, key, scancode, action, mods);
}
}
void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_MOUSE_BUTTON;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = PKE_INPUT_CURSOR_ENTERED_UNSET;
- ev.keyboardKeyAction = PKE_INPUT_KEYBOARD_KEY_ACTION_UNSET;
- ev.mouseButtonAction = InputMouseButtonAction{static_cast<InputMouseButtonAction_T>(action)};
- ev.windowFocused = PKE_INPUT_WINDOW_FOCUSED_UNSET;
- ev.x = 0;
- ev.y = 0;
- ev.button = button;
- ev.scanCode = 0;
- ev.mods = mods;
- ev.tickCount = 0;
+ if (registeredMouseButtonEvents.Count()) {
+ auto &ev = unhandledMouseButtonEvents.Push();
+ ev.button = button;
+ ev.mods = mods;
+ ev.action = action;
+ }
if (prevMouseButtonCallback) {
prevMouseButtonCallback(window, button, action, mods);
}
}
void ScrollCallback(GLFWwindow *window, double xOffset, double yOffset) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_SCROLL;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = PKE_INPUT_CURSOR_ENTERED_UNSET;
- ev.keyboardKeyAction = PKE_INPUT_KEYBOARD_KEY_ACTION_UNSET;
- ev.mouseButtonAction = PKE_INPUT_MOUSE_BUTTON_ACTION_UNSET;
- ev.windowFocused = PKE_INPUT_WINDOW_FOCUSED_UNSET;
- ev.x = xOffset;
- ev.y = yOffset;
- ev.button = 0;
- ev.scanCode = 0;
- ev.mods = 0;
- ev.tickCount = 0;
+ if (registeredScrollEvents.Count()) {
+ auto &ev = unhandledScrollEvents.Push();
+ ev.x = xOffset;
+ ev.y = yOffset;
+ }
if (prevScrollCallback) {
prevScrollCallback(window, xOffset, yOffset);
}
}
void WindowFocusCallback(GLFWwindow *window, int focused) {
- auto &ev = UnhandledPkeInputEvents.Push();
- ev.type = PKE_INPUT_EVENT_TYPE_WINDOW_FOCUS;
- ev.timePoint = pkeSettings.steadyClock.now();
- ev.cursorEntered = PKE_INPUT_CURSOR_ENTERED_UNSET;
- ev.keyboardKeyAction = PKE_INPUT_KEYBOARD_KEY_ACTION_UNSET;
- ev.mouseButtonAction = PKE_INPUT_MOUSE_BUTTON_ACTION_UNSET;
- ev.windowFocused = InputWindowFocused{static_cast<InputWindowFocused_T>(focused)};
- ev.x = 0;
- ev.y = 0;
- ev.button = 0;
- ev.scanCode = 0;
- ev.mods = 0;
- ev.tickCount = 0;
+ if (registeredWindowFocusEvents.Count()) {
+ auto &ev = unhandledWindowFocusEvents.Push();
+ ev.focused = focused;
+ }
if (prevWindowFocusCallback) {
prevWindowFocusCallback(window, focused);
}
@@ -185,13 +548,154 @@ void PkeInput_Init() {
prevWindowFocusCallback = glfwSetWindowFocusCallback(window, WindowFocusCallback);
}
+InputActionSetHandle PkeInput_RegisterSet(const PkeInputSet &set) {
+ InputActionSetHandle returnValue{static_cast<InputActionSetHandle_T>(registeredInputSets.Count())};
+ registeredInputSets.Push(set);
+ return returnValue;
+}
+
+void PkeInput_ActivateSet(InputActionSetHandle handle) {
+ InputActionSetHandle_T index{static_cast<InputActionSetHandle_T>(handle)};
+ activeInputSetStack.Push(handle);
+ auto &set = registeredInputSets[index];
+ for (int64_t i = 0; i < set.actionCount; ++i) {
+ PkeInputAction &action = set.actions[i];
+ // TODO doesn't support multiple masks - how do we align multiple event types?
+ // EX: strafe with keyboard + joystick
+ // creating multiple events doesn't make sense
+ // - have to keep in sync - isPressed ?
+ // - caller has to handle multiple scenarios
+ // Maybe we need a unifying event, but that defeats the purpose of this refactor and wastes memory
+ // Not to mention that the caller still has to know how to handle the unified response
+ // Some combinations of event types cannot be combined, so the caller has to know to ignore certain values
+ // Current design also has flaws
+ // The caller explicitly casts to the correct event type because we know the event type.
+ // If bindings were loaded dynamically, we would have to handle every scenario explicitly for every action
+ // Godot has some similarities - is_action_pressed(name) could hide the type, and Godot expects the
+ // programmer to know the input type in order to handle
+ // If we went for a more query-based approach - PkeInput_GetPressCount(actionTitle) for example
+ // there might be fewer oddities
+ // Maybe you just have to restrict certain actions to certain input types
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ action.eventIndex = registeredCursorEnterEvents.Count();
+ registeredCursorEnterEvents.Push(PkeCursorEnterEvent {
+ .sourceSet = handle,
+ .isEntered = lastCursorEntered,
+ });
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ action.eventIndex = registeredCursorPosEvents.Count();
+ registeredCursorPosEvents.Push(PkeCursorPosEvent {
+ .sourceSet = handle,
+ .xMotion = 0,
+ .yMotion = 0,
+ });
+ glfwGetCursorPos(window, &lastMousePos.x, &lastMousePos.y);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ action.eventIndex = registeredKeyEvents.Count();
+ registeredKeyEvents.Push(PkeKeyEvent {
+ .sourceSet = handle,
+ .button = action.primaryHash.button,
+ .mods = action.primaryHash.mods,
+ });
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ action.eventIndex = registeredMouseButtonEvents.Count();
+ registeredMouseButtonEvents.Push(PkeMouseButtonEvent {
+ .sourceSet = handle,
+ .button = action.primaryHash.button,
+ .mods = action.primaryHash.mods,
+ });
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ action.eventIndex = registeredScrollEvents.Count();
+ registeredScrollEvents.Push(PkeScrollEvent {
+ .sourceSet = handle,
+ .xMotion = 0,
+ .yMotion = 0,
+ });
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ action.eventIndex = registeredWindowFocusEvents.Count();
+ registeredWindowFocusEvents.Push(PkeWindowFocusEvent {
+ .sourceSet = handle,
+ .isFocused = lastWindowFocus,
+ });
+ }
+ }
+}
+
+void PkeInput_DeactivateSet(InputActionSetHandle handle) {
+ int64_t index = -1;
+ auto count = activeInputSetStack.Count();
+ for (int64_t i = 0; i < count; ++i) {
+ if (activeInputSetStack[i] == handle) {
+ index = i;
+ break;
+ }
+ }
+ assert(index >= 0 && "PkeInput_DeactivateSet - expected InputActionSet to be active");
+ assert(index == activeInputSetStack.Count() - 1 && "PkeInput_UnregisterSet - expected InputActionSet to be the last set active");
+ InputActionSetHandle_T handleIndex{static_cast<InputActionSetHandle_T>(handle)};
+ auto &set = registeredInputSets[handleIndex];
+ for (int64_t i = set.actionCount - 1; i >= 0; --i) {
+ PkeInputAction &action = set.actions[i];
+ // TODO doesn't support multiple masks - how do we align scroll + button
+ // WITHOUT having two events allocated?
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) {
+ registeredCursorEnterEvents.Remove(action.eventIndex);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) {
+ registeredCursorPosEvents.Remove(action.eventIndex);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) {
+ registeredKeyEvents.Remove(action.eventIndex);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) {
+ registeredMouseButtonEvents.Remove(action.eventIndex);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) {
+ registeredScrollEvents.Remove(action.eventIndex);
+ }
+ if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) {
+ registeredWindowFocusEvents.Remove(action.eventIndex);
+ }
+ }
+ activeInputSetStack.Pop();
+}
+
+void PkeInput_UnregisterSet(InputActionSetHandle handle) {
+ InputActionSetHandle_T index{static_cast<InputActionSetHandle_T>(handle)};
+ assert(index == registeredInputSets.Count() - 1 && "PkeInput_UnregisterSet - expected InputActionSet to be the last set registered");
+ const auto &set = registeredInputSets[index];
+ if (activeInputSetStack.Has(handle)) {
+ PkeInput_DeactivateSet(handle);
+ }
+ Pke_Delete<PkeInputAction>(set.actions, set.actionCount);
+ registeredInputSets.Remove(index);
+}
+
void PkeInput_Teardown() {
- UnhandledPkeInputEvents.~DynArray();
- if (prevWindowFocusCallback) { glfwSetWindowFocusCallback(window, prevWindowFocusCallback); }
- if (prevScrollCallback) { glfwSetScrollCallback(window, prevScrollCallback); }
- if (prevMouseButtonCallback) { glfwSetMouseButtonCallback(window, prevMouseButtonCallback); }
- if (prevKeyCallback) { glfwSetKeyCallback(window, prevKeyCallback); }
- if (prevCursorPosCallback) { glfwSetCursorPosCallback(window, prevCursorPosCallback); }
- if (prevCursorEnterCallback) { glfwSetCursorEnterCallback(window, prevCursorEnterCallback); }
+ glfwSetWindowFocusCallback(window, prevWindowFocusCallback);
+ glfwSetScrollCallback(window, prevScrollCallback);
+ glfwSetMouseButtonCallback(window, prevMouseButtonCallback);
+ glfwSetKeyCallback(window, prevKeyCallback);
+ glfwSetCursorPosCallback(window, prevCursorPosCallback);
+ glfwSetCursorEnterCallback(window, prevCursorEnterCallback);
+ unhandledCursorPosEvents.~DynArray();
+ unhandledCursorEnterEvents.~DynArray();
+ unhandledKeyEvents.~DynArray();
+ unhandledMouseButtonEvents.~DynArray();
+ unhandledScrollEvents.~DynArray();
+ unhandledWindowFocusEvents.~DynArray();
+ registeredCursorEnterEvents.~DynArray();
+ registeredCursorPosEvents.~DynArray();
+ registeredKeyEvents.~DynArray();
+ registeredMouseButtonEvents.~DynArray();
+ registeredScrollEvents.~DynArray();
+ registeredWindowFocusEvents.~DynArray();
+ activeInputSetStack.~DynArray();
+ registeredInputSets.~DynArray();
}