diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-11 16:04:48 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-11 16:04:54 -0400 |
| commit | 0f89d12e747b380b35143815a2c8e87c6ee752d4 (patch) | |
| tree | 78617e7cb819093aa9c0ad107b5dc79891e8ff55 | |
| parent | e478bae42cf886a12433331937887de4c4e85ce2 (diff) | |
pke: serialize PkeInput first-pass
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | editor/editor.cpp | 31 | ||||
| -rw-r--r-- | src/player-input.cpp | 241 | ||||
| -rw-r--r-- | src/player-input.hpp | 19 | ||||
| -rw-r--r-- | src/scene-types.hpp | 6 | ||||
| -rw-r--r-- | src/scene.cpp | 16 | ||||
| -rw-r--r-- | src/scene.hpp | 1 | ||||
| -rw-r--r-- | src/serialization-input.cpp | 207 | ||||
| -rw-r--r-- | src/serialization-input.hpp | 13 | ||||
| -rw-r--r-- | src/serialization.cpp | 14 | ||||
| -rw-r--r-- | src/serialization.hpp | 10 |
11 files changed, 415 insertions, 144 deletions
@@ -199,6 +199,7 @@ $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization-camera.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization-component.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization-font.$(OBJ_EXT) +$(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization-input.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/serialization-static-ui.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/static-cube.$(OBJ_EXT) $(DIR_OBJ)/libpke.$(LIB_EXT): $(DIR_OBJ)/static-plane.$(OBJ_EXT) diff --git a/editor/editor.cpp b/editor/editor.cpp index 959d772..b48a40e 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -1813,77 +1813,78 @@ void PkeEditor_Teardown() { } void PkeEditor_Init() { - PkeInputSet debugControlsSet; + PkeInputSet debugControlsSet{}; debugControlsSet.title = "debug-editor-controls"; debugControlsSet.actionCount = 14; debugControlsSet.actions = pk_new<PkeInputAction>(debugControlsSet.actionCount); + debugControlsSet.flags = PKE_INPUT_ACTION_SET_FLAG_DO_NOT_SERIALIZE; debugControlsSet.actions[0].name = dbgCtrl_CameraLeft; - debugControlsSet.actions[0].primaryHash = PkeInputEventMask { + debugControlsSet.actions[0].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_A, }; debugControlsSet.actions[1].name = dbgCtrl_CameraRight; - debugControlsSet.actions[1].primaryHash = PkeInputEventMask { + debugControlsSet.actions[1].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_D, }; debugControlsSet.actions[2].name = dbgCtrl_CameraForward; - debugControlsSet.actions[2].primaryHash = PkeInputEventMask { + debugControlsSet.actions[2].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_W, }; debugControlsSet.actions[3].name = dbgCtrl_CameraBack; - debugControlsSet.actions[3].primaryHash = PkeInputEventMask { + debugControlsSet.actions[3].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_S, }; debugControlsSet.actions[4].name = dbgCtrl_CameraUp; - debugControlsSet.actions[4].primaryHash = PkeInputEventMask { + debugControlsSet.actions[4].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_R, }; debugControlsSet.actions[5].name = dbgCtrl_CameraDown; - debugControlsSet.actions[5].primaryHash = PkeInputEventMask { + debugControlsSet.actions[5].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_F, }; debugControlsSet.actions[6].name = dbgCtrl_CameraRotCC; - debugControlsSet.actions[6].primaryHash = PkeInputEventMask { + debugControlsSet.actions[6].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_Q, }; debugControlsSet.actions[7].name = dbgCtrl_CameraRotC; - debugControlsSet.actions[7].primaryHash = PkeInputEventMask { + debugControlsSet.actions[7].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_E, }; debugControlsSet.actions[8].name = dbgCtrl_CameraRot; - debugControlsSet.actions[8].primaryHash = PkeInputEventMask { + debugControlsSet.actions[8].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_CURSOR_POS_EVENTS, }; debugControlsSet.actions[9].name = dbgCtrl_CameraButtonMask; - debugControlsSet.actions[9].primaryHash = PkeInputEventMask { + debugControlsSet.actions[9].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS, .button = GLFW_MOUSE_BUTTON_MIDDLE, }; debugControlsSet.actions[10].name = dbgCtrl_SelectHovered; - debugControlsSet.actions[10].primaryHash = PkeInputEventMask { + debugControlsSet.actions[10].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS, .button = GLFW_MOUSE_BUTTON_LEFT, }; debugControlsSet.actions[11].name = dbgCtrl_ClearSelection; - debugControlsSet.actions[11].primaryHash = PkeInputEventMask { + debugControlsSet.actions[11].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS, .button = GLFW_MOUSE_BUTTON_RIGHT, }; debugControlsSet.actions[12].name = dbgCtrl_DeleteSelectedItem; - debugControlsSet.actions[12].primaryHash = PkeInputEventMask { + debugControlsSet.actions[12].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_DELETE, }; debugControlsSet.actions[13].name = dbgCtrl_ImGui_Toggle; - debugControlsSet.actions[13].primaryHash = PkeInputEventMask { + debugControlsSet.actions[13].masks[0] = PkeInputEventMask { .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, .button = GLFW_KEY_F1, }; diff --git a/src/player-input.cpp b/src/player-input.cpp index 8ecc2cc..252d706 100644 --- a/src/player-input.cpp +++ b/src/player-input.cpp @@ -79,34 +79,35 @@ PkeInputAction *FindActionByName(const char *actionName) { } return nullptr; } -template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByAction(const PkeInputAction *inputAction, S *&activeEvent) { +template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByAction(const PkeInputAction *inputAction, S *&activeEvent, int32_t index) { activeEvent = nullptr; if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) { - activeEvent = ®isteredCursorEnterEvents[inputAction->eventIndex]; + activeEvent = ®isteredCursorEnterEvents[inputAction->event_indices[index]]; return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { - activeEvent = ®isteredCursorPosEvents[inputAction->eventIndex]; + activeEvent = ®isteredCursorPosEvents[inputAction->event_indices[index]]; return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { - activeEvent = ®isteredKeyEvents[inputAction->eventIndex]; + activeEvent = ®isteredKeyEvents[inputAction->event_indices[index]]; return PKE_INPUT_HASH_EVENT_TYPE_KEY; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { - activeEvent = ®isteredMouseButtonEvents[inputAction->eventIndex]; + activeEvent = ®isteredMouseButtonEvents[inputAction->event_indices[index]]; return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { - activeEvent = ®isteredScrollEvents[inputAction->eventIndex]; + activeEvent = ®isteredScrollEvents[inputAction->event_indices[index]]; return PKE_INPUT_HASH_EVENT_TYPE_SCROLL; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { - activeEvent = ®isteredWindowFocusEvents[inputAction->eventIndex]; + activeEvent = ®isteredWindowFocusEvents[inputAction->event_indices[index]]; 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; @@ -167,6 +168,7 @@ template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_B } return InputEventHash{0}; } +*/ template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_ByType(const PkeInputEventMask &mask, S *&activeEvent) { uint32_t count, i; activeEvent = nullptr; @@ -197,7 +199,7 @@ template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_B 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) { + for (int64_t l = 0; l < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++l) { PkeInputEventMask &evMask = inputAction.masks[l]; if ((evMask.computedHash & mask.computedHash) == InputEventHash{0}) { continue; @@ -219,27 +221,27 @@ template<InputEventHash T, typename S> InputEventHash FindActivePkeInputAction_B } } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) { - activeEvent = ®isteredCursorEnterEvents[inputAction.eventIndex]; + activeEvent = ®isteredCursorEnterEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { - activeEvent = ®isteredCursorPosEvents[inputAction.eventIndex]; + activeEvent = ®isteredCursorPosEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { - activeEvent = ®isteredKeyEvents[inputAction.eventIndex]; + activeEvent = ®isteredKeyEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_KEY; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { - activeEvent = ®isteredMouseButtonEvents[inputAction.eventIndex]; + activeEvent = ®isteredMouseButtonEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { - activeEvent = ®isteredScrollEvents[inputAction.eventIndex]; + activeEvent = ®isteredScrollEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_SCROLL; } if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { - activeEvent = ®isteredWindowFocusEvents[inputAction.eventIndex]; + activeEvent = ®isteredWindowFocusEvents[inputAction.event_indices[l]]; return PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS; } } @@ -438,30 +440,39 @@ 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; + for (int32_t i = 0; i < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++i) { + PkeInputEventMask event_mask = action->masks[i]; + if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER)) { + PkeCursorEnterEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER, PkeCursorEnterEvent>(action, event, i); + ev = event; + break; + } else if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS)) { + PkeCursorPosEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, PkeCursorPosEvent>(action, event, i); + ev = event; + break; + } else if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY)) { + PkeKeyEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_KEY, PkeKeyEvent>(action, event, i); + ev = event; + break; + } else if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON)) { + PkeMouseButtonEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON, PkeMouseButtonEvent>(action, event, i); + ev = event; + break; + } else if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL)) { + PkeScrollEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_SCROLL, PkeScrollEvent>(action, event, i); + ev = event; + break; + } else if (bool(event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS)) { + PkeWindowFocusEvent *event; + type = FindActivePkeInputAction_ByAction<PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS, PkeWindowFocusEvent>(action, event, i); + ev = event; + break; + } } return PkeInputEventHolder { .type = type, @@ -560,68 +571,55 @@ void PkeInput_ActivateSet(InputActionSetHandle 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.next; - PkeCursorEnterEvent ev{}; - ev.sourceSet = handle; - ev.isEntered = lastCursorEntered; - pk_arr_append_t(®isteredCursorEnterEvents, ev); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { - action.eventIndex = registeredCursorPosEvents.next; - PkeCursorPosEvent ev {}; - ev.sourceSet = handle; - ev.xMotion = 0; - ev.yMotion = 0; - pk_arr_append_t(®isteredCursorPosEvents, ev); - glfwGetCursorPos(window, &lastMousePos.x, &lastMousePos.y); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { - action.eventIndex = registeredKeyEvents.next; - PkeKeyEvent ev{}; - ev.sourceSet = handle; - ev.button = action.primaryHash.button; - ev.mods = action.primaryHash.mods; - pk_arr_append_t(®isteredKeyEvents, ev); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { - action.eventIndex = registeredMouseButtonEvents.next; - PkeMouseButtonEvent ev{}; - ev.sourceSet = handle; - ev.button = action.primaryHash.button; - ev.mods = action.primaryHash.mods; - pk_arr_append_t(®isteredMouseButtonEvents, ev); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { - action.eventIndex = registeredScrollEvents.next; - PkeScrollEvent ev{}; - ev.sourceSet = handle; - ev.xMotion = 0; - ev.yMotion = 0; - pk_arr_append_t(®isteredScrollEvents, ev); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { - action.eventIndex = registeredWindowFocusEvents.next; - PkeWindowFocusEvent ev{}; - ev.sourceSet = handle; - ev.isFocused = lastWindowFocus; - pk_arr_append_t(®isteredWindowFocusEvents, ev); + for (int k = 0; k < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++k) { + PkeInputEventMask event_mask = action.masks[k]; + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) { + action.event_indices[k] = registeredCursorEnterEvents.next; + PkeCursorEnterEvent ev{}; + ev.sourceSet = handle; + ev.isEntered = lastCursorEntered; + pk_arr_append_t(®isteredCursorEnterEvents, ev); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { + action.event_indices[k] = registeredCursorPosEvents.next; + PkeCursorPosEvent ev {}; + ev.sourceSet = handle; + ev.xMotion = 0; + ev.yMotion = 0; + pk_arr_append_t(®isteredCursorPosEvents, ev); + glfwGetCursorPos(window, &lastMousePos.x, &lastMousePos.y); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { + action.event_indices[k] = registeredKeyEvents.next; + PkeKeyEvent ev{}; + ev.sourceSet = handle; + ev.button = event_mask.button; + ev.mods = event_mask.mods; + pk_arr_append_t(®isteredKeyEvents, ev); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { + action.event_indices[k] = registeredMouseButtonEvents.next; + PkeMouseButtonEvent ev{}; + ev.sourceSet = handle; + ev.button = event_mask.button; + ev.mods = event_mask.mods; + pk_arr_append_t(®isteredMouseButtonEvents, ev); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { + action.event_indices[k] = registeredScrollEvents.next; + PkeScrollEvent ev{}; + ev.sourceSet = handle; + ev.xMotion = 0; + ev.yMotion = 0; + pk_arr_append_t(®isteredScrollEvents, ev); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { + action.event_indices[k] = registeredWindowFocusEvents.next; + PkeWindowFocusEvent ev{}; + ev.sourceSet = handle; + ev.isFocused = lastWindowFocus; + pk_arr_append_t(®isteredWindowFocusEvents, ev); + } } } } @@ -642,25 +640,26 @@ void PkeInput_DeactivateSet(InputActionSetHandle 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}) { - pk_arr_remove_at(®isteredCursorEnterEvents, action.eventIndex); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { - pk_arr_remove_at(®isteredCursorPosEvents, action.eventIndex); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { - pk_arr_remove_at(®isteredKeyEvents, action.eventIndex); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { - pk_arr_remove_at(®isteredMouseButtonEvents, action.eventIndex); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { - pk_arr_remove_at(®isteredScrollEvents, action.eventIndex); - } - if ((action.primaryHash.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { - pk_arr_remove_at(®isteredWindowFocusEvents, action.eventIndex); + for (int k = 0; k < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++k) { + PkeInputEventMask event_mask = action.masks[k]; + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != InputEventHash{0}) { + pk_arr_remove_at(®isteredCursorEnterEvents, action.event_indices[k]); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != InputEventHash{0}) { + pk_arr_remove_at(®isteredCursorPosEvents, action.event_indices[k]); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != InputEventHash{0}) { + pk_arr_remove_at(®isteredKeyEvents, action.event_indices[k]); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != InputEventHash{0}) { + pk_arr_remove_at(®isteredMouseButtonEvents, action.event_indices[k]); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != InputEventHash{0}) { + pk_arr_remove_at(®isteredScrollEvents, action.event_indices[k]); + } + if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != InputEventHash{0}) { + pk_arr_remove_at(®isteredWindowFocusEvents, action.event_indices[k]); + } } } pk_arr_remove_at(&activeInputSetStack, activeInputSetStack.next-1); @@ -681,6 +680,10 @@ void PkeInput_UnregisterSet(InputActionSetHandle handle) { pk_arr_remove_at(®isteredInputSets, index); } +pk_arr_t<PkeInputSet> &PkeInput_GetInputSets() { + return registeredInputSets; +} + void PkeInput_Teardown() { glfwSetWindowFocusCallback(window, prevWindowFocusCallback); glfwSetScrollCallback(window, prevScrollCallback); diff --git a/src/player-input.hpp b/src/player-input.hpp index f67e966..abb8a40 100644 --- a/src/player-input.hpp +++ b/src/player-input.hpp @@ -6,9 +6,13 @@ #include <cstdint> TypeSafeInt_H(InputActionSetHandle, uint8_t, 0xFF); - +TypeSafeInt_constexpr(InputActionSetFlags, uint8_t, 0xFF); TypeSafeInt_constexpr(InputEventHash, uint16_t, 0xFFFF); +constexpr InputActionSetFlags PKE_INPUT_ACTION_SET_FLAG_NONE = InputActionSetFlags{0x00}; +constexpr InputActionSetFlags PKE_INPUT_ACTION_SET_FLAG_DO_NOT_SERIALIZE = InputActionSetFlags{0x01}; +constexpr InputActionSetFlags PKE_INPUT_ACTION_SET_FLAG_AUTO_ENABLE = InputActionSetFlags{0x02}; + const InputEventHash PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER = InputEventHash {0x0001}; const InputEventHash PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS = InputEventHash {0x0002}; const InputEventHash PKE_INPUT_HASH_EVENT_TYPE_KEY = InputEventHash {0x0004}; @@ -94,19 +98,19 @@ struct PkeInputEventMask { int32_t mods = 0; }; -constexpr int64_t PKE_INPUT_ACTION_MASK_COUNT = 1; +#define PKE_INPUT_ACTION_MASK_INDEX_PRIMARY 0 +#define PKE_INPUT_ACTION_MASK_INDEX_SECONDARY 1 +#define PKE_INPUT_ACTION_MASK_INDEX_COUNT 2 struct PkeInputAction { const char *name; - union { - PkeInputEventMask masks[PKE_INPUT_ACTION_MASK_COUNT] = {{}}; - PkeInputEventMask primaryHash; - }; - int32_t eventIndex; + PkeInputEventMask masks[2] = {{},{}}; + int32_t event_indices[2] = {-1,-1}; }; struct PkeInputSet { const char *title; int64_t actionCount; PkeInputAction *actions; + InputActionSetFlags flags; }; void PkeInput_Tick(double delta); @@ -116,6 +120,7 @@ InputActionSetHandle PkeInput_RegisterSet(const PkeInputSet &set); void PkeInput_ActivateSet(InputActionSetHandle handle); void PkeInput_DeactivateSet(InputActionSetHandle handle); void PkeInput_UnregisterSet(InputActionSetHandle handle); +pk_arr_t<PkeInputSet> &PkeInput_GetInputSets(); void PkeInput_Teardown(); #endif /* PKE_PLAYER_INPUT_HPP */ diff --git a/src/scene-types.hpp b/src/scene-types.hpp index 655c621..d010d12 100644 --- a/src/scene-types.hpp +++ b/src/scene-types.hpp @@ -1,9 +1,10 @@ #ifndef PKE_SCENE_TYPES_HPP #define PKE_SCENE_TYPES_HPP -#include "pk.h" -#include "components.hpp" #include "camera.hpp" +#include "components.hpp" +#include "pk.h" +#include "player-input.hpp" const uint8_t SCENE_NAME_MAX_LEN = 16; #define pke_scene_name_printf_format "%16s" @@ -13,6 +14,7 @@ struct pke_scene : public Entity_Base { char name[SCENE_NAME_MAX_LEN] = {'\0'}; SceneHandle scene_handle = SceneHandle_MAX; pk_arr_t<CameraHandle> cameras; + pk_arr_t<InputActionSetHandle> input_handles; }; #endif /* PKE_SCENE_TYPES_HPP */ diff --git a/src/scene.cpp b/src/scene.cpp index ad6b502..2c47356 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -89,12 +89,17 @@ pk_bkt_arr *pke_scene_get_scenes() { } void pke_scene_remove(SceneHandle handle) { + uint32_t i; pke_scene *scn = &scene_mstr.bc[handle]; assert(scn != nullptr && "[pke_scene_remove] Failed to find scene by requested SceneHandle"); ECS_MarkForRemoval(scn); - for (long i = 0; i < scn->cameras.next; ++i) { + for (i = 0; i < scn->cameras.next; ++i) { PkeCamera_Destroy(scn->cameras[i]); } + for (i = 0; i < scn->input_handles.next; ++i) { + PkeInput_DeactivateSet(scn->input_handles[i]); + PkeInput_UnregisterSet(scn->input_handles[i]); + } if (scn->file_path.reserved > 0) { pk_delete<char>(scn->file_path.val, scn->file_path.reserved); } @@ -102,6 +107,7 @@ void pke_scene_remove(SceneHandle handle) { scn->name[0] = '\0'; scn->scene_handle = SceneHandle_MAX; pk_arr_reset(&scn->cameras); + pk_arr_reset(&scn->input_handles); pk_bkt_arr_free_handle(&scene_mstr.bc, handle); } @@ -112,3 +118,11 @@ void pke_scene_register_camera(SceneHandle scene_handle, CameraHandle cameraHand assert(scene != nullptr && "Failed to find scene by requested SceneHandle"); pk_arr_append(&scene->cameras, &cameraHandle); } + +void pke_scene_register_input_action_set(SceneHandle scene_handle, InputActionSetHandle handle) { + assert(scene_handle != SceneHandle_MAX); + assert(handle != InputActionSetHandle_MAX); + pke_scene *scene = pke_scene_get_by_handle(scene_handle); + assert(scene != nullptr && "Failed to find scene by requested SceneHandle"); + pk_arr_append_t(&scene->input_handles, handle); +} diff --git a/src/scene.hpp b/src/scene.hpp index 6e76987..6c80b39 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -16,5 +16,6 @@ pk_bkt_arr *pke_scene_get_scenes(); void pke_scene_remove(SceneHandle handle); void pke_scene_register_camera(SceneHandle scene_handle, CameraHandle cameraHandle); +void pke_scene_register_input_action_set(SceneHandle scene_handle, InputActionSetHandle handle); #endif /* PKE_SCENE_HPP */ diff --git a/src/serialization-input.cpp b/src/serialization-input.cpp new file mode 100644 index 0000000..e81665a --- /dev/null +++ b/src/serialization-input.cpp @@ -0,0 +1,207 @@ + +#include "serialization-input.hpp" + +#include "compile-time-assert.hpp" +#include "pk.h" +#include "scene.hpp" + +#include <cstring> + +pk_handle pke_serialize_input_action(srlztn_serialize_helper *h, PkeInputAction *action) { + char *s; + int len; + pke_kve kve{}; + pke_kve_container kvec{}; + + kvec.srlztn_handle = h->handle_head; + kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_INPUT_ACTION); + kvec.bkt = h->bkt; + kvec.arr.bkt = h->bkt; + kvec.children.bkt = h->bkt; + kvec.child_handles.bkt = h->bkt; + h->handle_head.itemIndex++; + + compt_a<40==sizeof(PkeInputAction)>(); + { + kve.key = SRLZTN_INPUT_ACTION_NAME; + len = strlen(action->name)+1; + s = pk_new<char>(len, h->bkt); + sprintf(s, "%s", action->name); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + for (int i = 0; i < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++i) { + if (action->masks[i].computedHash == InputEventHash{0}) { + continue; + } + { + kve.key = SRLZTN_INPUT_ACTION_MASK_HASH; + len = snprintf(NULL, 0, "0x%.4hX", static_cast<InputEventHash_T>(action->masks[i].computedHash)); + s = pk_new<char>(len+1, h->bkt); + sprintf(s, "0x%.4hX", static_cast<InputEventHash_T>(action->masks[i].computedHash)); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + { + kve.key = SRLZTN_INPUT_ACTION_MASK_BUTTON; + len = snprintf(NULL, 0, "%i", action->masks[i].button); + s = pk_new<char>(len+1, h->bkt); + sprintf(s, "%i", action->masks[i].button); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + { + kve.key = SRLZTN_INPUT_ACTION_MASK_MODS; + len = snprintf(NULL, 0, "%i", action->masks[i].mods); + s = pk_new<char>(len+1, h->bkt); + sprintf(s, "%i", action->masks[i].mods); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + } + + pk_arr_append_t(&h->kvp_containers, kvec); + return kvec.srlztn_handle; +} + +void pke_deserialize_input_action(srlztn_deserialize_helper *h, pke_kve_container *kvec, PkeInputAction &action) { + (void)h; + uint32_t i; + int32_t mask_index = -1; + char *s; + pke_kve *kve = nullptr; + PK_STN_RES stn_res = PK_STN_RES(0); + + compt_a<40==sizeof(PkeInputAction)>(); + for (i = 0; i < kvec->arr.next; ++i) { + kve = &kvec->arr[i]; + if (strncmp(kve->key, SRLZTN_INPUT_ACTION_NAME, strlen(SRLZTN_INPUT_ACTION_NAME)) == 0) { + // TODO specific bkt? + s = pk_new<char>(strlen(kve->val)+1, NULL); + sprintf(s, "%s", kve->key); + action.name = s; + continue; + } + if (strncmp(kve->key, SRLZTN_INPUT_ACTION_MASK_HASH, strlen(SRLZTN_INPUT_ACTION_MASK_HASH)) == 0) { + mask_index += 1; + assert(mask_index < PKE_INPUT_ACTION_MASK_INDEX_COUNT); + InputEventHash_T hash; + stn_res = pk_stn(&hash, kve->val, NULL, 16); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing '%s' primary from: '%s'\n", __FILE__, stn_res, SRLZTN_INPUT_ACTION_MASK_HASH, kve->val); + continue; + } + action.masks[mask_index].computedHash = InputEventHash{hash}; + continue; + } + if (strncmp(kve->key, SRLZTN_INPUT_ACTION_MASK_BUTTON, strlen(SRLZTN_INPUT_ACTION_MASK_BUTTON)) == 0) { + assert(mask_index >= 0); + assert(mask_index < PKE_INPUT_ACTION_MASK_INDEX_COUNT); + stn_res = pk_stn(&action.masks[mask_index].button, kve->val, NULL); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing '%s' primary from: '%s'\n", __FILE__, stn_res, SRLZTN_INPUT_ACTION_MASK_BUTTON, kve->val); + } + continue; + } + if (strncmp(kve->key, SRLZTN_INPUT_ACTION_MASK_MODS, strlen(SRLZTN_INPUT_ACTION_MASK_MODS)) == 0) { + assert(mask_index >= 0); + assert(mask_index < PKE_INPUT_ACTION_MASK_INDEX_COUNT); + stn_res = pk_stn(&action.masks[mask_index].mods, kve->val, NULL); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing '%s' primary from: '%s'\n", __FILE__, stn_res, SRLZTN_INPUT_ACTION_MASK_MODS, kve->val); + } + continue; + } + } +} + +pk_handle pke_serialize_input_set(srlztn_serialize_helper *h, PkeInputSet *input_set) { + char *s; + int len; + pke_kve kve{}; + pke_kve_container kvec{}; + + kvec.srlztn_handle = h->handle_head; + kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_INPUT_SET); + kvec.bkt = h->bkt; + kvec.arr.bkt = h->bkt; + kvec.children.bkt = h->bkt; + kvec.child_handles.bkt = h->bkt; + h->handle_head.itemIndex++; + + for (int i = 0; i < input_set->actionCount; ++i) { + pk_handle child_handle = pke_serialize_input_action(h, &input_set->actions[i]); + pk_arr_append_t(&kvec.child_handles, child_handle); + } + + compt_a<32==sizeof(PkeInputSet)>(); + { + kve.key = SRLZTN_INPUT_SET_TITLE; + len = strlen(input_set->title)+1; + s = pk_new<char>(len, h->bkt); + sprintf(s, "%s", input_set->title); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + { + kve.key = SRLZTN_INPUT_SET_FLAGS; + len = snprintf(NULL, 0, "0x%.04X", static_cast<InputActionSetFlags_T>(input_set->flags)); + s = pk_new<char>(len+1, h->bkt); + sprintf(s, "0x%.04X", static_cast<InputActionSetFlags_T>(input_set->flags)); + kve.val = s; + kve.end = SRLZTN_KVE_END; + pk_arr_append_t(&kvec.arr, kve); + } + + pk_arr_append_t(&h->kvp_containers, kvec); + return kvec.srlztn_handle; +} + +void pke_deserialize_input_set(srlztn_deserialize_helper *h, pke_kve_container *kvec) { + (void)h; + uint32_t i, k; + char *s; + pke_kve *kve = nullptr; + PkeInputSet set{}; + PK_STN_RES stn_res = PK_STN_RES(0); + + // TODO specific bucket + set.actionCount = kvec->children.next; + set.actions = pk_new<PkeInputAction>(kvec->children.next, NULL); + for (k = 0; k < set.actionCount; ++k) { + pke_deserialize_input_action(h, kvec->children[k], set.actions[k]); + } + + compt_a<40==sizeof(PkeInputAction)>(); + for (i = 0; i < kvec->arr.next; ++i) { + kve = &kvec->arr[i]; + if (strncmp(kve->key, SRLZTN_INPUT_SET_TITLE, strlen(SRLZTN_INPUT_SET_TITLE)) == 0) { + // TODO specific bkt? + s = pk_new<char>(strlen(kve->val)+1, NULL); + sprintf(s, "%s", kve->key); + set.title = s; + continue; + } + if (strncmp(kve->key, SRLZTN_INPUT_SET_FLAGS, strlen(SRLZTN_INPUT_SET_FLAGS)) == 0) { + InputActionSetFlags_T flags; + stn_res = pk_stn(&flags, kve->val, NULL, 16); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing '%s' primary from: '%s'\n", __FILE__, stn_res, SRLZTN_INPUT_SET_FLAGS, kve->val); + continue; + } + set.flags = InputActionSetFlags{flags}; + continue; + } + } + + InputActionSetHandle action_set_handle = PkeInput_RegisterSet(set); + pke_scene_register_input_action_set(h->scene->scene_handle, action_set_handle); + if (PK_HAS_FLAG(set.flags, PKE_INPUT_ACTION_SET_FLAG_AUTO_ENABLE)) { + PkeInput_ActivateSet(action_set_handle); + } +} diff --git a/src/serialization-input.hpp b/src/serialization-input.hpp new file mode 100644 index 0000000..6a7dde3 --- /dev/null +++ b/src/serialization-input.hpp @@ -0,0 +1,13 @@ +#ifndef PKE_SERIALIZATION_INPUT_HPP +#define PKE_SERIALIZATION_INPUT_HPP + +#include "player-input.hpp" +#include "serialization.hpp" + +pk_handle pke_serialize_input_action(srlztn_serialize_helper *h, PkeInputAction *action); +void pke_deserialize_input_action(srlztn_deserialize_helper *h, pke_kve_container *kvec); + +pk_handle pke_serialize_input_set(srlztn_serialize_helper *h, PkeInputSet *input_set); +void pke_deserialize_input_set(srlztn_deserialize_helper *h, pke_kve_container *kvec); + +#endif /* PKE_SERIALIZATION_INPUT_HPP */ diff --git a/src/serialization.cpp b/src/serialization.cpp index e7e1d4c..3bd589d 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -2,11 +2,13 @@ #include "serialization.hpp" #include "font.hpp" #include "pk.h" +#include "player-input.hpp" #include "serialization-component.hpp" #include "serialization-camera.hpp" #include "camera.hpp" #include "ecs.hpp" #include "serialization-font.hpp" +#include "serialization-input.hpp" #include "serialization-static-ui.hpp" #include "static-ui.hpp" @@ -69,6 +71,14 @@ void pke_serialize_scene(srlztn_serialize_helper *h) { CamIterFn cam_iter_cb{}; InstIterFn inst_iter_cb{}; + pk_arr_t<PkeInputSet> &sets = PkeInput_GetInputSets(); + for (uint32_t i = 0; i < sets.next; ++i) { + if (PK_HAS_FLAG(sets[i].flags, PKE_INPUT_ACTION_SET_FLAG_DO_NOT_SERIALIZE)) { + continue; + } + pke_serialize_input_set(h, &sets[i]); + } + FontTypeIndex font_type_count; FontType *fonts = FontType_GetFonts(font_type_count); for (FontTypeIndex_T b = 0; b < (FontTypeIndex_T)font_type_count; ++b) { @@ -110,6 +120,10 @@ void pke_deserialize_scene(srlztn_deserialize_helper *h) { for (i = 0; i < h->kvp_containers.next; ++i) { kvec = &h->kvp_containers[i]; + if (strcmp(kvec->type_code.val, SRLZTN_OBJ_INPUT_SET) == 0) { + pke_deserialize_input_set(h, kvec); + continue; + } if (strcmp(kvec->type_code.val, SRLZTN_OBJ_FONT_RENDER) == 0) { pke_deserialize_font_render(h, kvec); continue; diff --git a/src/serialization.hpp b/src/serialization.hpp index e26667f..fe7d427 100644 --- a/src/serialization.hpp +++ b/src/serialization.hpp @@ -26,6 +26,8 @@ iccsc SRLZTN_OBJ_UI_BOX = "UIBox"; iccsc SRLZTN_OBJ_FONT_RENDER = "FontRender"; iccsc SRLZTN_OBJ_FONT_RENDER_SETTINGS = "FontRenderSettings"; iccsc SRLZTN_OBJ_UI_BOX_TYPE_DATA = "UIBoxTypeData"; +iccsc SRLZTN_OBJ_INPUT_ACTION = "InputAction"; +iccsc SRLZTN_OBJ_INPUT_SET = "InputSet"; iccsc SRLZTN_POSROT_POS = "Position:"; iccsc SRLZTN_POSROT_ROT = "Rotation:"; @@ -68,6 +70,14 @@ iccsc SRLZTN_UI_FONT_RENDER_SETTINGS_SURFACE_AREA_SIZE = "SurfaceAreaSize:"; iccsc SRLZTN_UI_FONT_RENDER_SETTINGS_SURFACE_AREA_POS = "SurfaceAreaPos:"; iccsc SRLZTN_UI_FONT_RENDER_SETTINGS_SURFACE_AREA_FLAGS = "SurfaceAreaFlags:"; +iccsc SRLZTN_INPUT_ACTION_NAME = "Name:"; +iccsc SRLZTN_INPUT_ACTION_MASK_HASH = "MaskHash:"; +iccsc SRLZTN_INPUT_ACTION_MASK_BUTTON = "MaskButton:"; +iccsc SRLZTN_INPUT_ACTION_MASK_MODS = "MaskMods:"; + +iccsc SRLZTN_INPUT_SET_TITLE = "Title:"; +iccsc SRLZTN_INPUT_SET_FLAGS = "Flags:"; + struct srlztn_ecs_mapping { pk_uuid serialized_uuid = pk_uuid_zed; Entity_Base *created_entity = nullptr; |
