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/cardslot.cpp
src/icons.cpp
src/menu.cpp
src/manamenu.cpp
src/usb_descriptors.c

View File

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

View File

@ -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;

6
src/menu.cpp Normal file
View File

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