diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 695424f..3a32da9 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(lib_engine OBJECT mempool.c entManager.c render_queue.c + keymaps.c ) target_link_libraries(lib_engine PUBLIC diff --git a/engine/keymaps.c b/engine/keymaps.c new file mode 100644 index 0000000..249b879 --- /dev/null +++ b/engine/keymaps.c @@ -0,0 +1,155 @@ +#include "keymaps.h" +#include "raylib.h" + +/** + * The raylib's version doesn't cover all keys, + * so manually create the name for each relevant key. + * + * Since it is a string, need them to exist statically. + * So do a static table. + * + * Separate table for different ranges to save a little + * memory? + * + * This is the dumb but straightforward way. + * May be memory-inefficient and a little slow. + * + */ + +static const char* KEYNAMES_MAPPING_39[] = { + [KEY_APOSTROPHE-39] = "'", + [1] = "", + [2] = "", + [3] = "", + [4] = "", + [KEY_COMMA-39] = ",", + [KEY_MINUS-39] = "-", + [KEY_PERIOD-39] = ",", + [KEY_SLASH-39] = "/", + [KEY_ZERO-39] = "0", + [KEY_ONE-39] = "1", + [KEY_TWO-39] = "2", + [KEY_THREE-39] = "3", + [KEY_FOUR-39] = "4", + [KEY_FIVE-39] = "5", + [KEY_SIX-39] = "6", + [KEY_SEVEN-39] = "7", + [KEY_EIGHT-39] = "8", + [KEY_NINE-39] = "9", + [KEY_SEMICOLON-39] = ";", + [KEY_EQUAL-39] = "=", + [KEY_A-39] = "A", + [KEY_B-39] = "B", + [KEY_C-39] = "C", + [KEY_D-39] = "D", + [KEY_E-39] = "E", + [KEY_F-39] = "F", + [KEY_G-39] = "G", + [KEY_H-39] = "H", + [KEY_I-39] = "I", + [KEY_J-39] = "J", + [KEY_K-39] = "K", + [KEY_L-39] = "L", + [KEY_M-39] = "M", + [KEY_N-39] = "N", + [KEY_O-39] = "O", + [KEY_P-39] = "P", + [KEY_Q-39] = "Q", + [KEY_R-39] = "R", + [KEY_S-39] = "S", + [KEY_T-39] = "T", + [KEY_U-39] = "U", + [KEY_V-39] = "V", + [KEY_W-39] = "W", + [KEY_X-39] = "X", + [KEY_Y-39] = "Y", + [KEY_Z-39] = "Z", + [KEY_LEFT_BRACKET-39] = "[", + [KEY_BACKSLASH-39] = "\\", + [KEY_RIGHT_BRACKET-39] = "]", + [KEY_GRAVE-39] = "`", +}; + +//Mapping for key after 255 +static const char* KEYNAMES_MAPPING_256[] = { + [KEY_ESCAPE-256] = "", + [KEY_ENTER-256] = "", + [KEY_TAB-256] = "TAB", + [KEY_BACKSPACE-256] = "", + [KEY_INSERT-256] = "INSERT", + [KEY_DELETE-256] = "DELETE", + [KEY_RIGHT-256] = "RIGHT", + [KEY_LEFT-256] = "LEFT", + [KEY_DOWN-256] = "DOWN", + [KEY_UP-256] = "UP", + [KEY_PAGE_UP-256] = "PG UP", + [KEY_PAGE_DOWN-256] = "PG DOWN", + [KEY_HOME-256] = "HOME", + [KEY_END-256] = "END", + [KEY_CAPS_LOCK-256] = "CAPLOCKS", + [KEY_SCROLL_LOCK-256] = "SCR LCK", + [KEY_NUM_LOCK-256] = "", + [KEY_PRINT_SCREEN-256] = "PRT SCN", + [KEY_PAUSE-256] = "PAUSE", + [KEY_F1-256] = "F1", + [KEY_F2-256] = "F2", + [KEY_F3-256] = "F3", + [KEY_F4-256] = "F4", + [KEY_F5-256] = "F5", + [KEY_F6-256] = "F6", + [KEY_F7-256] = "F7", + [KEY_F8-256] = "F8", + [KEY_F9-256] = "F9", + [KEY_F10-256] = "F10", + [KEY_F11-256] = "F11", + [KEY_F12-256] = "F12", + [KEY_LEFT_SHIFT-256] = "LSHIFT", + [KEY_LEFT_CONTROL-256] = "LCTRL", + [KEY_LEFT_ALT-256] = "LALT", + [KEY_LEFT_SUPER-256] = "", + [KEY_RIGHT_SHIFT-256] = "RSHIFT", + [KEY_RIGHT_CONTROL-256] = "RCTRL", + [KEY_RIGHT_ALT-256] = "RALT", + [KEY_RIGHT_SUPER-256] = "", + [KEY_KB_MENU-256] = "", + [KEY_KP_0-256] = "KPad 0", + [KEY_KP_1-256] = "KPad 1", + [KEY_KP_2-256] = "KPad 2", + [KEY_KP_3-256] = "KPad 3", + [KEY_KP_4-256] = "KPad 4", + [KEY_KP_5-256] = "KPad 5", + [KEY_KP_6-256] = "KPad 6", + [KEY_KP_7-256] = "KPad 7", + [KEY_KP_8-256] = "KPad 8", + [KEY_KP_9-256] = "KPad 9", + [KEY_KP_DECIMAL-256] = "", + [KEY_KP_DIVIDE-256] = "", + [KEY_KP_MULTIPLY-256] = "", + [KEY_KP_SUBTRACT-256] = "", + [KEY_KP_ADD-256] = "", + [KEY_KP_ENTER-256] = "", + [KEY_KP_EQUAL-256] = "", +}; + +const char* ExtGetKeyName(int key) +{ + + if (key >= KEY_ESCAPE) + { + key -= KEY_ESCAPE; + return KEYNAMES_MAPPING_256[key]; + } + + if (key >= KEY_APOSTROPHE) + { + key -= KEY_APOSTROPHE; + return KEYNAMES_MAPPING_39[key]; + } + + if (key == KEY_SPACE) + { + return "SPACE"; + } + + return ""; +} diff --git a/engine/keymaps.h b/engine/keymaps.h new file mode 100644 index 0000000..f85dc6e --- /dev/null +++ b/engine/keymaps.h @@ -0,0 +1,5 @@ +#ifndef KEYMAPS_H +#define KEYMAPS_H + +const char* ExtGetKeyName(int key); +#endif diff --git a/scenes/options_scene.c b/scenes/options_scene.c index 1834e0b..14ad728 100644 --- a/scenes/options_scene.c +++ b/scenes/options_scene.c @@ -1,42 +1,179 @@ #include "scene_impl.h" #include "assets_tag.h" +#include "keymaps.h" #include +/** + * A potential performance tweak is to reduce the lookup. + * The number of configurable actions should be fixed and + * therefore would be known on scene init. + * + * So delegate all lookup on scene init. + * Then, only call lookup on key changes. + */ + +static const char* get_action_name(ActionType_t action) { + /** + * This is sort of a hack to get it done. + * In theory, the engine should provide a way to register a name for an action + * However, i didn't plan that far and this is the only place that needs it + * Maybe in the next version of the engine... + * + * I could hardcode this to be array, but nah... + */ + switch (action) { + case ACTION_UP: + return "Up"; + case ACTION_DOWN: + return "Down"; + case ACTION_LEFT: + return "Left"; + case ACTION_RIGHT: + return "Right"; + case ACTION_JUMP: + case ACTION_CONFIRM: + return "Confirm/Jump"; + case ACTION_EXIT: + return "Return"; + case ACTION_LOOKAHEAD: + return "Look"; + default: + return "Undefined"; + } +} + static void options_scene_render_func(Scene_t* scene) { - //OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); + OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); - int key; - ActionType_t action; - char buffer[16]; + KeyBindInfo_t keybind_info; + char buffer[64]; int y_offset = 16; + uint16_t line = 0; BeginTextureMode(scene->layers.render_layers[0].layer_tex); - sc_map_foreach(&scene->engine->keybinds, action, key) { - sprintf(buffer, "Action %d : %d", action, key); - DrawText(buffer, 32, y_offset, 12, WHITE); - y_offset += 12; + ClearBackground((Color){0,0,0,0}); + + if (line == data->curr_selection) + { + DrawText(">>", 0, y_offset, 12, WHITE); } float vol = GetMasterVolume(); sprintf(buffer, "Volume : %.1f", vol); DrawText(buffer, 32, y_offset, 12, WHITE); + y_offset += 12; + line++; + + sc_array_foreach(&data->keybinds_info, keybind_info) { + if (line == data->curr_selection) + { + DrawText(">>", 0, y_offset, 12, WHITE); + } + sprintf(buffer, "%s : %s %d", keybind_info.action_name, keybind_info.key_name, keybind_info.key); + DrawText(buffer, 32, y_offset, 12, WHITE); + y_offset += 12; + line++; + } + + if (line == data->curr_selection) + { + DrawText(">>", 0, y_offset, 12, WHITE); + } + DrawText("OK", 32, y_offset, 12, WHITE); + y_offset += 12; + line++; + + if (line == data->curr_selection) + { + DrawText(">>", 0, y_offset, 12, WHITE); + } + DrawText("Cancel", 32, y_offset, 12, WHITE); + y_offset += 12; + line++; + EndTextureMode(); } +static void exec_component_function(Scene_t* scene, uint16_t sel) +{ + printf("Sel: %u\n", sel); + if (sel == 0) + { + // Volume option, does nothing + return; + } + sel--; + + uint16_t n_binds = sc_map_size_64(&scene->engine->keybinds); + if (sel >= n_binds) + { + // Either OK or Cancel + // Both will return to menu scene + sel -= n_binds; + // TODO: add check to save keybinds + + change_scene(scene->engine, MAIN_MENU_SCENE); + } + else + { + // Keybind options + // TODO: This should change the scene mode + // Engine need to record last key released + } +} + static void options_do_action(Scene_t* scene, ActionType_t action, bool pressed) { - switch(action) + OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); + + switch(data->mode) { - case ACTION_EXIT: + case OPTIONS_NORMAL_MODE: + { + uint16_t new_selection = data->curr_selection; if (!pressed) { - if(scene->engine != NULL) + switch(action) { - change_scene(scene->engine, MAIN_MENU_SCENE); + case ACTION_UP: + if (new_selection > 0) + { + data->curr_selection--; + } + break; + case ACTION_DOWN: + if (new_selection < data->n_selections - 1) + { + data->curr_selection++; + } + break; + case ACTION_LEFT: + // Left and right only works on volume option + if (new_selection == 0) + { + } + break; + case ACTION_RIGHT: + if (new_selection == 0) + { + } + break; + case ACTION_CONFIRM: + exec_component_function(scene, new_selection); + break; + case ACTION_EXIT: + if(scene->engine != NULL) + { + change_scene(scene->engine, MAIN_MENU_SCENE); + } + break; + default: + break; } } + } break; - default: + case OPTIONS_KEYBIND_MODE: break; } } @@ -54,6 +191,34 @@ void init_options_scene(OptionScene_t* scene) scene->scene.engine->intended_window_size.y } ); + + scene->data.curr_selection = 0; + scene->data.mode = OPTIONS_NORMAL_MODE; + + // 3 extra options: Volume, Ok, Cancel + scene->data.n_selections = sc_map_size_64(&scene->scene.engine->keybinds) + 3; + + + sc_array_init(&scene->data.keybinds_info); + + { + int key; + ActionType_t action; + sc_map_foreach(&scene->scene.engine->keybinds, action, key) + { + KeyBindInfo_t keybind = { + .action_name = get_action_name(action), + .key_name = ExtGetKeyName(key), + .action = action, + .key = key, + }; + sc_array_add(&scene->data.keybinds_info, keybind); + } + } + + // The number of actions that can be key-binds is constant. + // So can just init once. + sc_array_add(&scene->scene.systems, &options_scene_render_func); sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_UP, KEY_UP), ACTION_UP); @@ -63,10 +228,12 @@ void init_options_scene(OptionScene_t* scene) sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); + sc_map_put_64(&scene->scene.action_map, KEY_ENTER, ACTION_CONFIRM); sc_map_put_64(&scene->scene.action_map, KEY_BACKSPACE, ACTION_EXIT); } void free_options_scene(OptionScene_t* scene) { + sc_array_term(&scene->data.keybinds_info); free_scene(&scene->scene); } diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index 77cf127..5ad5ac2 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -135,12 +135,24 @@ typedef struct LevelSelectScene { LevelSelectSceneData_t data; } LevelSelectScene_t; -enum OptionSceneMode { +typedef enum OptionSceneMode { OPTIONS_NORMAL_MODE, OPTIONS_KEYBIND_MODE, -}; -typedef struct OptionSceneData { +}OptionSceneMode_t; +typedef struct KeyBindInfo { + const char* action_name; + const char* key_name; + int action; + int key; +}KeyBindInfo_t; +sc_array_def(KeyBindInfo_t, keybinds); + +typedef struct OptionSceneData { + struct sc_array_keybinds keybinds_info; // Selection index -> keybind info + uint16_t n_selections; + uint16_t curr_selection; + OptionSceneMode_t mode; }OptionSceneData_t; typedef struct OptionScene {