From fb000d7275ebe7ffe931eac52e5d2e80cd324894 Mon Sep 17 00:00:00 2001 From: shylie Date: Tue, 13 Jan 2026 02:36:25 -0500 Subject: [PATCH] Add cmc menu --- CMakeLists.txt | 1 + include/display.h | 1 + include/menu.h | 125 +++++++++++++++++++++++++++++++++++++++++++- src/cmcmenu.cpp | 98 +++++++++++++++++++++++++++++++++++ src/display.cpp | 11 ++++ src/main.cpp | 43 ++++------------ src/manamenu.cpp | 129 ++++++++++++++-------------------------------- src/menu.cpp | 5 ++ 8 files changed, 289 insertions(+), 124 deletions(-) create mode 100644 src/cmcmenu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 98de19d..988e6a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(mtgcard src/icons.cpp src/menu.cpp src/manamenu.cpp + src/cmcmenu.cpp src/usb_descriptors.c diff --git a/include/display.h b/include/display.h index 38476c6..9cd9f3a 100644 --- a/include/display.h +++ b/include/display.h @@ -19,6 +19,7 @@ public: uint16_t height); PixelStream pixels(); + void clear(); private: uint8_t sck, tx, cs, dc; diff --git a/include/menu.h b/include/menu.h index ac4ab93..8ff7fdb 100644 --- a/include/menu.h +++ b/include/menu.h @@ -3,6 +3,8 @@ #include "display.h" +#include +#include #include class Menu @@ -14,6 +16,7 @@ public: virtual ~Menu() = default; virtual void onTick(float dt) = 0; + virtual void onResume() = 0; virtual void onLeftPressed() = 0; virtual void onLeftHeld() = 0; @@ -28,6 +31,66 @@ protected: lib::Display* const display; }; +namespace ease +{ +// adapted from easings.net +inline float inOutElastic(float x) +{ + constexpr float c5 = (2 * 3.1415926f) / 4.5f; + + if (x == 0) + { + return 0; + } + if (x == 1) + { + return 1; + } + if (x < 0.5) + { + return -powf(2, 20 * x - 10) * sinf((20 * x - 11.125f) * c5) / 2.0f; + } + else + { + return powf(2, -20 * x + 10) * sinf((20 * x - 11.25f) * c5) / 2.0f + 1; + } +} + +// adapted from easings.net +inline float outElastic(float x) +{ + constexpr float c4 = (2 * 3.1415926f) / 3; + + if (x == 0) + { + return 0; + } + if (x == 1) + { + return 1; + } + return powf(2, -10 * x) * sinf((x * 10 - 0.75f) * c4) + 1; +} + +// adapted from easings.net +inline float inElastic(float x) +{ + constexpr float c4 = (2 * 3.1415926f) / 3; + + if (x == 0) + { + return 0; + } + if (x == 1) + { + return 1; + } + + return -powf(2, 10 * x - 10) * sinf((x * 10 - 10.75f) * c4); +} + +} + namespace menus { @@ -38,6 +101,7 @@ public: ~ManaMenu() override = default; void onTick(float dt) override; + void onResume() override; void onLeftPressed() override; void onLeftHeld() override; @@ -51,11 +115,68 @@ public: private: uint8_t current; uint8_t previous; - bool going_left; + bool going_right; float progress; }; -constexpr size_t MAX_MENU_SIZE = sizeof(ManaMenu); +class CMCMenu : public Menu +{ +public: + explicit CMCMenu(lib::Display& display, uint8_t color); + ~CMCMenu() override = default; + + void onTick(float dt) override; + void onResume() override; + + void onLeftPressed() override; + void onLeftHeld() override; + + void onMenuPressed() override; + void onMenuHeld() override; + + void onRightPressed() override; + void onRightHeld() override; + +private: + uint8_t color; + uint8_t current; + uint8_t previous; + float progress; +}; + +namespace detail +{ + +union Menus +{ + ManaMenu mana; + CMCMenu cmc; +}; +} + +constexpr size_t MAX_MENU_COUNT = 5; + +extern uint8_t MENU_MEMORY[sizeof(detail::Menus) * MAX_MENU_COUNT]; +extern int8_t current_menu; + +inline Menu* get_current_menu() +{ + return reinterpret_cast(MENU_MEMORY + + current_menu * sizeof(detail::Menus)); +} + +template +inline void push_menu(lib::Display& display, Args&&... args) +{ + current_menu += 1; + new (get_current_menu()) T(display, args...); +} +inline void pop_menu() +{ + get_current_menu()->~Menu(); + current_menu -= 1; + get_current_menu()->onResume(); +} } diff --git a/src/cmcmenu.cpp b/src/cmcmenu.cpp new file mode 100644 index 0000000..ab4e6e4 --- /dev/null +++ b/src/cmcmenu.cpp @@ -0,0 +1,98 @@ +#include "icons.h" +#include "menu.h" +#include "pixelstream.h" + +using namespace menus; + +CMCMenu::CMCMenu(lib::Display& display, uint8_t color) : + Menu(display), + color(color), + current(2), + previous(1), + progress(0.7f) +{ + display.clear(); +} + +void CMCMenu::onTick(float dt) +{ + constexpr float CENTER_X = 120; + constexpr float CENTER_Y = 160; + constexpr float DT_SCALE = 1.4f; + constexpr uint8_t STEP = 48; + constexpr uint8_t ERASE_DATA[39 * 5 * 3] = {}; + + if (progress < 1.0f) + { + for (int8_t dcmc = -1; dcmc <= 1; dcmc++) + { + const int8_t dir = (previous > current ? 1 : -1); + const int8_t cmc_to_draw = current + dir * dcmc; + + if (cmc_to_draw < 0 || cmc_to_draw > 20) + { + continue; + } + + const float offset + = dir * ease::outElastic(progress) * STEP + (dir * (dcmc - 1)) * STEP; + + // left + { + display->set_update_area(CENTER_X - 20 + offset, CENTER_Y - 20, 5, 39); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 39 * 5 * 3); + } + // right + { + display->set_update_area(CENTER_X - 20 + offset + 37, CENTER_Y - 20, 5, + 39); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 39 * 5 * 3); + } + + // draw new + { + display->set_update_area(CENTER_X - 15 + offset, CENTER_Y - 15, 31, + 32); + auto pixels = display->pixels(); + pixels.write(icon::NUMBER_ICONS[cmc_to_draw], icon::LENGTH); + } + } + + progress += dt * DT_SCALE; + + if (progress >= 0.75f) + { + progress = 1.0f; + } + } +} +void CMCMenu::onResume() {} + +void CMCMenu::onLeftPressed() +{ + if (progress >= 1 && current > 0) + { + previous = current; + current -= 1; + + progress = 0; + } +} +void CMCMenu::onLeftHeld() {} + +void CMCMenu::onMenuPressed() { pop_menu(); } +void CMCMenu::onMenuHeld() {} + +void CMCMenu::onRightPressed() +{ + if (progress >= 1 && current < 20) + { + previous = current; + current += 1; + + progress = 0; + } +} +void CMCMenu::onRightHeld() {} diff --git a/src/display.cpp b/src/display.cpp index 21afc5a..2458a73 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -100,6 +100,17 @@ void Display::set_update_area(uint16_t left, uint16_t top, uint16_t width, PixelStream Display::pixels() { return PixelStream(*this); } +void Display::clear() +{ + set_update_area(0, 0, 240, 320); + + auto stream = pixels(); + for (int i = 0; i < 240 * 320; i++) + { + stream.write(0, 0, 0); + } +} + void Display::send_command(uint8_t command) { send_command(command, nullptr, 0); diff --git a/src/main.cpp b/src/main.cpp index b348db4..e1394e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include "menu.h" #include "pixelstream.h" -#include #include #include #include @@ -27,9 +26,9 @@ bi_decl(bi_ptr_int32(0x1111, 1, FLASH_RX, 28)); bi_decl(bi_ptr_int32(0x1111, 1, FLASH_CS, 29)); bi_decl(bi_program_feature_group(0x1111, 2, "Buttons")); -bi_decl(bi_ptr_int32(0x1111, 2, BUTTON_LEFT, 20)); +bi_decl(bi_ptr_int32(0x1111, 2, BUTTON_LEFT, 8)); bi_decl(bi_ptr_int32(0x1111, 2, BUTTON_MIDDLE, 0)); -bi_decl(bi_ptr_int32(0x1111, 2, BUTTON_RIGHT, 8)); +bi_decl(bi_ptr_int32(0x1111, 2, BUTTON_RIGHT, 20)); Display display(DISPLAY_SCK, DISPLAY_TX, DISPLAY_CS, DISPLAY_DC, 120000000); Flash flash(FLASH_SCK, FLASH_TX, FLASH_RX, FLASH_CS, 70000000); @@ -46,7 +45,6 @@ enum class RX struct { - struct { uint8_t buffer[32]; @@ -68,27 +66,6 @@ struct int32_t card_index = 0; } rx; -uint8_t - MENU_MEMORY[menus::MAX_MENU_SIZE * 5]; // menu stack is at most 5 menus deep -int8_t current_menu = -1; - -Menu* get_current_menu() -{ - return reinterpret_cast(MENU_MEMORY - + current_menu * menus::MAX_MENU_SIZE); -} - -template void push_menu() -{ - current_menu += 1; - new (get_current_menu()) T(display); -} -void pop_menu() -{ - get_current_menu()->~Menu(); - current_menu -= 1; -} - } int main() @@ -113,7 +90,7 @@ int main() absolute_time_t last_press = get_absolute_time(); absolute_time_t previous_time = last_press; - push_menu(); + menus::push_menu(display); while (true) { @@ -121,31 +98,31 @@ int main() float dt = absolute_time_diff_us(previous_time, current) / 1000000.0f; if (!gpio_get(BUTTON_LEFT) - && absolute_time_diff_us(last_press, current) > 1000 * 150) + && absolute_time_diff_us(last_press, current) > 1000 * 1000) { - get_current_menu()->onLeftPressed(); + menus::get_current_menu()->onLeftPressed(); last_press = current; } if (!gpio_get(BUTTON_MIDDLE) - && absolute_time_diff_us(last_press, current) > 1000 * 150) + && absolute_time_diff_us(last_press, current) > 1000 * 1000) { - get_current_menu()->onMenuPressed(); + menus::get_current_menu()->onMenuPressed(); last_press = current; } if (!gpio_get(BUTTON_RIGHT) - && absolute_time_diff_us(last_press, current) > 1000 * 150) + && absolute_time_diff_us(last_press, current) > 1000 * 1000) { - get_current_menu()->onRightPressed(); + menus::get_current_menu()->onRightPressed(); last_press = current; } tud_task(); - get_current_menu()->onTick(dt); + menus::get_current_menu()->onTick(dt); previous_time = current; } diff --git a/src/manamenu.cpp b/src/manamenu.cpp index ff0c8a5..b71ade2 100644 --- a/src/manamenu.cpp +++ b/src/manamenu.cpp @@ -9,62 +9,6 @@ namespace constexpr uint8_t COLORS[] = { 0, 0b1, 0b10, 0b100, 0b1000, 0b10000 }; -// adapted from easings.net -float easeInOutElastic(float x) -{ - constexpr float c5 = (2 * 3.1415926f) / 4.5f; - - if (x == 0) - { - return 0; - } - if (x == 1) - { - return 1; - } - if (x < 0.5) - { - return -powf(2, 20 * x - 10) * sinf((20 * x - 11.125f) * c5) / 2.0f; - } - else - { - return powf(2, -20 * x + 10) * sinf((20 * x - 11.25f) * c5) / 2.0f + 1; - } -} - -// adapted from easings.net -float easeOutElastic(float x) -{ - constexpr float c4 = (2 * 3.1415926f) / 3; - - if (x == 0) - { - return 0; - } - if (x == 1) - { - return 1; - } - return powf(2, -10 * x) * sinf((x * 10 - 0.75f) * c4) + 1; -} - -// adapted from easings.net -float easeInElastic(float x) -{ - constexpr float c4 = (2 * 3.1415926f) / 3; - - if (x == 0) - { - return 0; - } - if (x == 1) - { - return 1; - } - - return -powf(2, 10 * x - 10) * sinf((x * 10 - 10.75f) * c4); -} - } using namespace menus; @@ -73,8 +17,8 @@ ManaMenu::ManaMenu(lib::Display& display) : Menu(display), current(0), previous(0), - going_left(false), - progress(0.99f) + going_right(true), + progress(0.7f) { } @@ -93,7 +37,7 @@ void ManaMenu::onTick(float dt) if (progress < 1.0f) { const float offset - = (1.0f - easeOutElastic(progress)) * MAX_OFFSET + RADIUS; + = (1.0f - ease::outElastic(progress)) * MAX_OFFSET + RADIUS; // erase old { @@ -125,8 +69,8 @@ void ManaMenu::onTick(float dt) else if (progress < 2.0f) { const float offset - = (going_left ? -1 : 1) * STEP * easeOutElastic(progress - 1) - + STEP / 2.0f + (going_left ? 2 * STEP : 0); + = (going_right ? -1 : 1) * STEP * ease::outElastic(progress - 1) + + STEP / 2.0f + (going_right ? 2 * STEP : 0); // erase previous for (int i = 0; i < sizeof(COLORS) / sizeof(*COLORS); i++) @@ -193,7 +137,8 @@ void ManaMenu::onTick(float dt) } else if (progress < 3.0f) { - const float offset = easeOutElastic(progress - 2.0f) * MAX_OFFSET + RADIUS; + const float offset + = ease::outElastic(progress - 2.0f) * MAX_OFFSET + RADIUS; // erase old { @@ -223,6 +168,12 @@ void ManaMenu::onTick(float dt) } } } +void ManaMenu::onResume() +{ + display->clear(); + progress = 0.7f; + going_right = true; +} void ManaMenu::onLeftPressed() { @@ -231,33 +182,7 @@ void ManaMenu::onLeftPressed() return; } - going_left = true; - - previous = current; - if (current == 0) - { - current = 5; - } - else - { - current -= 1; - } - - progress = 0.0f; -} -void ManaMenu::onLeftHeld() {} - -void ManaMenu::onMenuPressed() {} -void ManaMenu::onMenuHeld() {} - -void ManaMenu::onRightPressed() -{ - if (progress < 3.0f) - { - return; - } - - going_left = false; + going_right = false; previous = current; if (current == 5) @@ -271,4 +196,30 @@ void ManaMenu::onRightPressed() progress = 0.0f; } +void ManaMenu::onLeftHeld() {} + +void ManaMenu::onMenuPressed() { push_menu(*display, current); } +void ManaMenu::onMenuHeld() {} + +void ManaMenu::onRightPressed() +{ + if (progress < 3.0f) + { + return; + } + + going_right = true; + + previous = current; + if (current == 0) + { + current = 5; + } + else + { + current -= 1; + } + + progress = 0.0f; +} void ManaMenu::onRightHeld() {} diff --git a/src/menu.cpp b/src/menu.cpp index 181dbcd..f3180cc 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -1,5 +1,10 @@ #include "menu.h" +#include "pixelstream.h" + +decltype(menus::current_menu) menus::current_menu; +decltype(menus::MENU_MEMORY) menus::MENU_MEMORY; + Menu::Menu(lib::Display& display) : display(&display) {