From bec441bd960978675a9b8b4f7750d8b06f49f367 Mon Sep 17 00:00:00 2001 From: shylie Date: Sun, 11 Jan 2026 16:47:46 -0500 Subject: [PATCH] Add selection 'highlight', ease movement --- CMakeLists.txt | 1 + include/menu.h | 1 + src/manamenu.cpp | 179 ++++++++++++++++++++++++++++++++++++++--------- src/menu.cpp | 6 ++ 4 files changed, 153 insertions(+), 34 deletions(-) create mode 100644 src/menu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b82cd1..98de19d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(mtgcard src/flash.cpp src/cardslot.cpp src/icons.cpp + src/menu.cpp src/manamenu.cpp src/usb_descriptors.c diff --git a/include/menu.h b/include/menu.h index 6397b63..ac4ab93 100644 --- a/include/menu.h +++ b/include/menu.h @@ -50,6 +50,7 @@ public: private: uint8_t current; + uint8_t previous; bool going_left; float progress; }; diff --git a/src/manamenu.cpp b/src/manamenu.cpp index 4483524..f24aeee 100644 --- a/src/manamenu.cpp +++ b/src/manamenu.cpp @@ -9,20 +9,72 @@ 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; -Menu::Menu(lib::Display& display) : - display(&display) -{ -} - ManaMenu::ManaMenu(lib::Display& display) : Menu(display), current(0), + previous(0), going_left(false), - progress(0.999f) + progress(0.99f) { } @@ -30,11 +82,51 @@ void ManaMenu::onTick(float dt) { constexpr float PI = 3.1415926f; constexpr float STEP = 2 * PI / 6.0f; - constexpr float RADIUS = 80; + constexpr float RADIUS = 75; + constexpr float CENTER_X = 120; + constexpr float CENTER_Y = 190; + constexpr float MAX_OFFSET = RADIUS / 1.5f; + constexpr float DT_SCALE_ROTATE = 1.1f; + constexpr float DT_SCALE_UPDOWN = 1.6f; + constexpr uint8_t ERASE_DATA[38 * 5 * 3] = {}; if (progress < 1.0f) { - const float offset = (going_left ? -1 : 1) * STEP * progress + STEP / 2.0f; + const float offset + = (1.0f - easeOutElastic(progress)) * MAX_OFFSET + RADIUS; + + // erase old + { + display->set_update_area(CENTER_X - 20, CENTER_Y - 20 - offset, 38, 5); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 38 * 5 * 3); + } + { + display->set_update_area(CENTER_X - 20, CENTER_Y - 15 + 30 - offset, 38, + 5); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 38 * 5 * 3); + } + + // write new + { + display->set_update_area(CENTER_X - 15, CENTER_Y - 15 - offset, 31, 32); + auto pixels = display->pixels(); + const uint8_t* data = icon::wubrgc(COLORS[previous]); + pixels.write(data, icon::LENGTH); + } + + progress += dt * DT_SCALE_UPDOWN; + if (progress > 0.75f) + { + progress = 1.0f; + } + } + else if (progress < 2.0f) + { + const float offset + = (going_left ? -1 : 1) * STEP * easeOutElastic(progress - 1) + + STEP / 2.0f; // erase previous for (int i = 0; i < sizeof(COLORS) / sizeof(*COLORS); i++) @@ -44,54 +136,42 @@ void ManaMenu::onTick(float dt) const float x = cosf(angle) * RADIUS; const float y = sinf(angle) * RADIUS; - const int left = x - 20 + 120; - const int top = y - 20 + 160; + const int left = x - 20 + CENTER_X; + const int top = y - 20 + CENTER_Y; // top rectangle { display->set_update_area(left, top, 38, 5); auto pixels = display->pixels(); - for (int pixel = 0; pixel < 38 * 5; pixel++) - { - pixels.write(0, 0, 0); - } + pixels.write(ERASE_DATA, 38 * 5 * 3); } // bottom rectangle { display->set_update_area(left, top + 36, 38, 5); auto pixels = display->pixels(); - for (int pixel = 0; pixel < 38 * 5; pixel++) - { - pixels.write(0, 0, 0); - } + pixels.write(ERASE_DATA, 38 * 5 * 3); } // left rectangle { display->set_update_area(left, top + 3, 5, 38); auto pixels = display->pixels(); - for (int pixel = 0; pixel < 5 * 38; pixel++) - { - pixels.write(0, 0, 0); - } + pixels.write(ERASE_DATA, 38 * 5 * 3); } // right rectangle { display->set_update_area(left + 36, top + 3, 5, 38); auto pixels = display->pixels(); - for (int pixel = 0; pixel < 5 * 38; pixel++) - { - pixels.write(0, 0, 0); - } + pixels.write(ERASE_DATA, 38 * 5 * 3); } } - progress += dt * 2.0f; - if (progress > 1.0f) + progress += dt * DT_SCALE_ROTATE; + if (progress > 1.75f) { - progress = 1.0f; + progress = 2.0f; } // write new @@ -102,28 +182,58 @@ void ManaMenu::onTick(float dt) const float x = cosf(angle) * RADIUS; const float y = sinf(angle) * RADIUS; - const int left = x - 15 + 120; - const int top = y - 15 + 160; + const int left = x - 15 + CENTER_X; + const int top = y - 15 + CENTER_Y; display->set_update_area(left, top, 31, 32); auto pixels = display->pixels(); const uint8_t* data = icon::wubrgc(COLORS[i]); pixels.write(data, icon::LENGTH); } + } + else if (progress < 3.0f) + { + const float offset = easeOutElastic(progress - 2.0f) * MAX_OFFSET + RADIUS; - sleep_ms(1); + // erase old + { + display->set_update_area(CENTER_X - 20, CENTER_Y - 20 - offset, 38, 5); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 38 * 5 * 3); + } + { + display->set_update_area(CENTER_X - 20, CENTER_Y - 15 + 30 - offset, 38, + 5); + auto pixels = display->pixels(); + pixels.write(ERASE_DATA, 38 * 5 * 3); + } + + // write new + { + display->set_update_area(CENTER_X - 15, CENTER_Y - 15 - offset, 31, 32); + auto pixels = display->pixels(); + const uint8_t* data = icon::wubrgc(COLORS[current]); + pixels.write(data, icon::LENGTH); + } + + progress += dt * DT_SCALE_UPDOWN; + if (progress > 2.75f) + { + progress = 3.0f; + } } } void ManaMenu::onLeftPressed() { - if (progress < 1.0f) + if (progress < 3.0f) { return; } going_left = true; + previous = current; if (current == 0) { current = 5; @@ -142,13 +252,14 @@ void ManaMenu::onMenuHeld() {} void ManaMenu::onRightPressed() { - if (progress < 1.0f) + if (progress < 3.0f) { return; } going_left = false; + previous = current; if (current == 5) { current = 0; diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 0000000..181dbcd --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,6 @@ +#include "menu.h" + +Menu::Menu(lib::Display& display) : + display(&display) +{ +}