Add selection 'highlight', ease movement

This commit is contained in:
shylie 2026-01-11 16:47:46 -05:00
parent 03cb418d63
commit bec441bd96
4 changed files with 153 additions and 34 deletions

View File

@ -14,6 +14,7 @@ add_executable(mtgcard
src/flash.cpp src/flash.cpp
src/cardslot.cpp src/cardslot.cpp
src/icons.cpp src/icons.cpp
src/menu.cpp
src/manamenu.cpp src/manamenu.cpp
src/usb_descriptors.c src/usb_descriptors.c

View File

@ -50,6 +50,7 @@ public:
private: private:
uint8_t current; uint8_t current;
uint8_t previous;
bool going_left; bool going_left;
float progress; float progress;
}; };

View File

@ -9,20 +9,72 @@ namespace
constexpr uint8_t COLORS[] = { 0, 0b1, 0b10, 0b100, 0b1000, 0b10000 }; 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; using namespace menus;
Menu::Menu(lib::Display& display) :
display(&display)
{
}
ManaMenu::ManaMenu(lib::Display& display) : ManaMenu::ManaMenu(lib::Display& display) :
Menu(display), Menu(display),
current(0), current(0),
previous(0),
going_left(false), 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 PI = 3.1415926f;
constexpr float STEP = 2 * PI / 6.0f; 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) 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 // erase previous
for (int i = 0; i < sizeof(COLORS) / sizeof(*COLORS); i++) 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 x = cosf(angle) * RADIUS;
const float y = sinf(angle) * RADIUS; const float y = sinf(angle) * RADIUS;
const int left = x - 20 + 120; const int left = x - 20 + CENTER_X;
const int top = y - 20 + 160; const int top = y - 20 + CENTER_Y;
// top rectangle // top rectangle
{ {
display->set_update_area(left, top, 38, 5); display->set_update_area(left, top, 38, 5);
auto pixels = display->pixels(); auto pixels = display->pixels();
for (int pixel = 0; pixel < 38 * 5; pixel++) pixels.write(ERASE_DATA, 38 * 5 * 3);
{
pixels.write(0, 0, 0);
}
} }
// bottom rectangle // bottom rectangle
{ {
display->set_update_area(left, top + 36, 38, 5); display->set_update_area(left, top + 36, 38, 5);
auto pixels = display->pixels(); auto pixels = display->pixels();
for (int pixel = 0; pixel < 38 * 5; pixel++) pixels.write(ERASE_DATA, 38 * 5 * 3);
{
pixels.write(0, 0, 0);
}
} }
// left rectangle // left rectangle
{ {
display->set_update_area(left, top + 3, 5, 38); display->set_update_area(left, top + 3, 5, 38);
auto pixels = display->pixels(); auto pixels = display->pixels();
for (int pixel = 0; pixel < 5 * 38; pixel++) pixels.write(ERASE_DATA, 38 * 5 * 3);
{
pixels.write(0, 0, 0);
}
} }
// right rectangle // right rectangle
{ {
display->set_update_area(left + 36, top + 3, 5, 38); display->set_update_area(left + 36, top + 3, 5, 38);
auto pixels = display->pixels(); auto pixels = display->pixels();
for (int pixel = 0; pixel < 5 * 38; pixel++) pixels.write(ERASE_DATA, 38 * 5 * 3);
{
pixels.write(0, 0, 0);
}
} }
} }
progress += dt * 2.0f; progress += dt * DT_SCALE_ROTATE;
if (progress > 1.0f) if (progress > 1.75f)
{ {
progress = 1.0f; progress = 2.0f;
} }
// write new // write new
@ -102,28 +182,58 @@ void ManaMenu::onTick(float dt)
const float x = cosf(angle) * RADIUS; const float x = cosf(angle) * RADIUS;
const float y = sinf(angle) * RADIUS; const float y = sinf(angle) * RADIUS;
const int left = x - 15 + 120; const int left = x - 15 + CENTER_X;
const int top = y - 15 + 160; const int top = y - 15 + CENTER_Y;
display->set_update_area(left, top, 31, 32); display->set_update_area(left, top, 31, 32);
auto pixels = display->pixels(); auto pixels = display->pixels();
const uint8_t* data = icon::wubrgc(COLORS[i]); const uint8_t* data = icon::wubrgc(COLORS[i]);
pixels.write(data, icon::LENGTH); 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() void ManaMenu::onLeftPressed()
{ {
if (progress < 1.0f) if (progress < 3.0f)
{ {
return; return;
} }
going_left = true; going_left = true;
previous = current;
if (current == 0) if (current == 0)
{ {
current = 5; current = 5;
@ -142,13 +252,14 @@ void ManaMenu::onMenuHeld() {}
void ManaMenu::onRightPressed() void ManaMenu::onRightPressed()
{ {
if (progress < 1.0f) if (progress < 3.0f)
{ {
return; return;
} }
going_left = false; going_left = false;
previous = current;
if (current == 5) if (current == 5)
{ {
current = 0; current = 0;

6
src/menu.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "menu.h"
Menu::Menu(lib::Display& display) :
display(&display)
{
}