Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LED button press fade across all themes. #813

Merged
merged 17 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions lib/AnimationStation/src/Animation.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
#include "Animation.hpp"

#include "AnimationStation.hpp"

#define PRESS_COOLDOWN_INCREMENT 500
#define PRESS_COOLDOWN_MAX 5000
#define PRESS_COOLDOWN_MIN 0

LEDFormat Animation::format;
std::map<uint32_t, int32_t> Animation::times = {};
std::map<uint32_t, RGB> Animation::hitColor = {};

Animation::Animation(PixelMatrix &matrix) : matrix(&matrix) {
for (size_t r = 0; r != matrix.pixels.size(); r++) {
for (size_t c = 0; c != matrix.pixels[r].size(); c++) {
if (matrix.pixels[r][c].index == NO_PIXEL.index)
continue;
times.insert_or_assign(matrix.pixels[r][c].index, 0);
hitColor.insert_or_assign(matrix.pixels[r][c].index, defaultColor);
}
}
}

void Animation::UpdatePixels(std::vector<Pixel> inpixels) {
this->pixels = inpixels;
}

void Animation::UpdateTime() {
coolDownTimeInMs = AnimationStation::options.buttonPressColorCooldownTimeInMs;

absolute_time_t currentTime = get_absolute_time();
updateTimeInMs = absolute_time_diff_us(lastUpdateTime, currentTime) / 1000;
lastUpdateTime = currentTime;
}

void Animation::UpdatePresses(RGB (&frame)[100]) {
// Queue up blend on hit
for (size_t p = 0; p < pixels.size(); p++) {
if (pixels[p].index != NO_PIXEL.index) {
times[pixels[p].index] = coolDownTimeInMs;
hitColor[pixels[p].index] = frame[pixels[p].positions[0]];
}
}
}

void Animation::DecrementFadeCounter(int32_t index) {
times[index] -= updateTimeInMs;
if (times[index] < 0) {
times[index] = 0;
};
}

void Animation::ClearPixels() {
this->pixels.clear();
}
Expand All @@ -28,3 +69,38 @@ bool Animation::notInFilter(Pixel pixel) {

return true;
}

RGB Animation::BlendColor(RGB start, RGB end, uint32_t timeRemainingInMs) {
RGB result = ColorBlack;

if (timeRemainingInMs <= 0) {
return end;
}

float progress = 1.0f - (static_cast<float>(timeRemainingInMs) / static_cast<float>(coolDownTimeInMs));
if (progress < 0.0f) progress = 0.0f;
if (progress > 1.0f) progress = 1.0f;

result.r = static_cast<uint32_t>(static_cast<float>(start.r + (end.r - start.r) * progress));
result.g = static_cast<uint32_t>(static_cast<float>(start.g + (end.g - start.g) * progress));
result.b = static_cast<uint32_t>(static_cast<float>(start.b + (end.b - start.b) * progress));

return result;
}


void Animation::FadeTimeUp() {
AnimationStation::options.buttonPressColorCooldownTimeInMs = AnimationStation::options.buttonPressColorCooldownTimeInMs + PRESS_COOLDOWN_INCREMENT;

if (AnimationStation::options.buttonPressColorCooldownTimeInMs > PRESS_COOLDOWN_MAX) {
AnimationStation::options.buttonPressColorCooldownTimeInMs = PRESS_COOLDOWN_MAX;
}
}

void Animation::FadeTimeDown() {
AnimationStation::options.buttonPressColorCooldownTimeInMs = AnimationStation::options.buttonPressColorCooldownTimeInMs - PRESS_COOLDOWN_INCREMENT;

if (AnimationStation::options.buttonPressColorCooldownTimeInMs > PRESS_COOLDOWN_MAX) {
AnimationStation::options.buttonPressColorCooldownTimeInMs = PRESS_COOLDOWN_MIN;
}
}
19 changes: 19 additions & 0 deletions lib/AnimationStation/src/Animation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "pico/stdlib.h"
#include <vector>
#include "NeoPico.hpp"
#include <map>

struct RGB {
// defaults allows trivial constructor, avoiding compiler complaints and avoiding unnessecary initialization
Expand Down Expand Up @@ -113,16 +114,34 @@ class Animation {

bool notInFilter(Pixel pixel);
virtual void Animate(RGB (&frame)[100]) = 0;
void UpdateTime();
void UpdatePresses(RGB (&frame)[100]);
void DecrementFadeCounter(int32_t index);

virtual void ParameterUp() = 0;
virtual void ParameterDown() = 0;

virtual void FadeTimeUp();
virtual void FadeTimeDown();

RGB BlendColor(RGB start, RGB end, uint32_t frame);

protected:
/* We track both the full matrix as well as individual pixels here to support
button press changes. Rather than adjusting the matrix to represent a subset of pixels,
we provide a subset of pixels to use as a filter. */
PixelMatrix *matrix;
std::vector<Pixel> pixels;
bool filtered = false;

// Color fade
RGB defaultColor = ColorBlack;
static std::map<uint32_t, int32_t> times;
static std::map<uint32_t, RGB> hitColor;
absolute_time_t lastUpdateTime = nil_time;
uint32_t coolDownTimeInMs = 1000;
int64_t updateTimeInMs = 20;

};

#endif
8 changes: 8 additions & 0 deletions lib/AnimationStation/src/AnimationStation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ void AnimationStation::HandleEvent(AnimationHotkey action) {
if (action == HOTKEY_LEDS_PRESS_PARAMETER_DOWN) {
this->buttonAnimation->ParameterDown();
}

if (action == HOTKEY_LEDS_FADETIME_UP) {
this->baseAnimation->FadeTimeUp();
}

if (action == HOTKEY_LEDS_FADETIME_DOWN) {
this->baseAnimation->FadeTimeDown();
}

}

Expand Down
6 changes: 4 additions & 2 deletions lib/AnimationStation/src/AnimationStation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ typedef enum
HOTKEY_LEDS_PRESS_PARAMETER_DOWN,
HOTKEY_LEDS_PARAMETER_DOWN,
HOTKEY_LEDS_BRIGHTNESS_UP,
HOTKEY_LEDS_BRIGHTNESS_DOWN
HOTKEY_LEDS_BRIGHTNESS_DOWN,
HOTKEY_LEDS_FADETIME_UP,
HOTKEY_LEDS_FADETIME_DOWN
} AnimationHotkey;

struct __attribute__ ((__packed__)) AnimationOptions
Expand Down Expand Up @@ -88,7 +90,7 @@ struct __attribute__ ((__packed__)) AnimationOptions
uint32_t customThemeR3Pressed;
uint32_t customThemeA1Pressed;
uint32_t customThemeA2Pressed;
uint32_t customThemeCooldownTimeInMs;
uint32_t buttonPressColorCooldownTimeInMs;
};

class AnimationStation
Expand Down
20 changes: 12 additions & 8 deletions lib/AnimationStation/src/Effects/Chase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@ void Chase::Animate(RGB (&frame)[100]) {
return;
}

UpdateTime();
UpdatePresses(frame);

for (auto &col : matrix->pixels) {
for (auto &pixel : col) {
if (pixel.index == NO_PIXEL.index)
continue;

// Count down the timer
DecrementFadeCounter(pixel.index);

if (this->IsChasePixel(pixel.index)) {
RGB color = RGB::wheel(this->WheelFrame(pixel.index));
for (auto &pos : pixel.positions)
frame[pos] = color;
}
else {
frame[pos] = BlendColor(hitColor[pixel.index], color, times[pixel.index]);
} else {
for (auto &pos : pixel.positions)
frame[pos] = ColorBlack;
frame[pos] = BlendColor(hitColor[pixel.index], ColorBlack, times[pixel.index]);
}
}
}
Expand Down Expand Up @@ -52,10 +57,9 @@ void Chase::Animate(RGB (&frame)[100]) {
}

// this really shouldn't be nessecary, but something outside the param down might be changing this
if ( AnimationStation::options.chaseCycleTime < CHASE_CYCLE_MIN ){
if (AnimationStation::options.chaseCycleTime < CHASE_CYCLE_MIN) {
AnimationStation::options.chaseCycleTime = CHASE_CYCLE_MIN;
}
else if (AnimationStation::options.chaseCycleTime > CHASE_CYCLE_MAX) {
} else if (AnimationStation::options.chaseCycleTime > CHASE_CYCLE_MAX) {
AnimationStation::options.chaseCycleTime = CHASE_CYCLE_MAX;
}

Expand Down Expand Up @@ -106,7 +110,7 @@ void Chase::ParameterUp() {

void Chase::ParameterDown() {
AnimationStation::options.chaseCycleTime = AnimationStation::options.chaseCycleTime - CHASE_CYCLE_INCREMENT;
if ( AnimationStation::options.chaseCycleTime < CHASE_CYCLE_MIN ){
if (AnimationStation::options.chaseCycleTime < CHASE_CYCLE_MIN) {
AnimationStation::options.chaseCycleTime = CHASE_CYCLE_MIN;
}
}
107 changes: 24 additions & 83 deletions lib/AnimationStation/src/Effects/CustomTheme.cpp
Original file line number Diff line number Diff line change
@@ -1,107 +1,48 @@
#include "CustomTheme.hpp"

#define PRESS_COOLDOWN_INCREMENT 500
#define PRESS_COOLDOWN_MAX 5000
#define PRESS_COOLDOWN_MIN 0

std::map<uint32_t, RGB> CustomTheme::theme;
std::map<uint32_t, int32_t> CustomTheme::times = {};
std::map<uint32_t, RGB> CustomTheme::hitColor = {};

CustomTheme::CustomTheme(PixelMatrix &matrix) : Animation(matrix) {
for (size_t r = 0; r != matrix.pixels.size(); r++) {
for (size_t c = 0; c != matrix.pixels[r].size(); c++) {
if (matrix.pixels[r][c].index == NO_PIXEL.index)
continue;
times.insert_or_assign(matrix.pixels[r][c].index, 0);
hitColor.insert_or_assign(matrix.pixels[r][c].index, defaultColor);
}
}
}

void CustomTheme::UpdatePixels(std::vector<Pixel> inpixels) {
this->pixels = inpixels;
}

void CustomTheme::Animate(RGB (&frame)[100]) {
coolDownTimeInMs = AnimationStation::options.customThemeCooldownTimeInMs;

absolute_time_t currentTime = get_absolute_time();
int64_t updateTimeInMs = absolute_time_diff_us(lastUpdateTime, currentTime) / 1000;
lastUpdateTime = currentTime;

for (size_t p = 0; p < pixels.size(); p++) {
if (pixels[p].index != NO_PIXEL.index) {
times[pixels[p].index] = coolDownTimeInMs;
hitColor[pixels[p].index] = frame[pixels[p].positions[0]];
UpdateTime();
UpdatePresses(frame);

for (size_t r = 0; r != matrix->pixels.size(); r++) {
for (size_t c = 0; c != matrix->pixels[r].size(); c++) {
if (matrix->pixels[r][c].index == NO_PIXEL.index)
continue;

// Count down the timer
DecrementFadeCounter(matrix->pixels[r][c].index);

auto itr = theme.find(matrix->pixels[r][c].mask);
if (itr != theme.end()) {
for (size_t p = 0; p != matrix->pixels[r][c].positions.size(); p++) {
// Interpolate from hitColor (color the button was assigned when pressed) back to the theme color
frame[matrix->pixels[r][c].positions[p]] = BlendColor(hitColor[matrix->pixels[r][c].index], itr->second, times[matrix->pixels[r][c].index]);
}
}

for (size_t r = 0; r != matrix->pixels.size(); r++) {
for (size_t c = 0; c != matrix->pixels[r].size(); c++) {
if (matrix->pixels[r][c].index == NO_PIXEL.index)
continue;

// Count down the timer
times[matrix->pixels[r][c].index] -= updateTimeInMs;
if (times[matrix->pixels[r][c].index] < 0) {
times[matrix->pixels[r][c].index] = 0;
};

auto itr = theme.find(matrix->pixels[r][c].mask);
if (itr != theme.end()) {
for (size_t p = 0; p != matrix->pixels[r][c].positions.size(); p++) {
// Interpolate from hitColor (color the button was assigned when pressed) back to the theme color
frame[matrix->pixels[r][c].positions[p]] = BlendColor(hitColor[matrix->pixels[r][c].index], itr->second, times[matrix->pixels[r][c].index]);
}
} else {
for (size_t p = 0; p != matrix->pixels[r][c].positions.size(); p++) {
frame[matrix->pixels[r][c].positions[p]] = defaultColor;
}
}
} else {
for (size_t p = 0; p != matrix->pixels[r][c].positions.size(); p++) {
frame[matrix->pixels[r][c].positions[p]] = defaultColor;
}
}
}
}
}

bool CustomTheme::HasTheme() {
return CustomTheme::theme.size() > 0;
return CustomTheme::theme.size() > 0;
}

void CustomTheme::SetCustomTheme(std::map<uint32_t, RGB> customTheme) {
CustomTheme::theme = customTheme;
AnimationStation::effectCount = TOTAL_EFFECTS + 1;
CustomTheme::theme = customTheme;
AnimationStation::effectCount = TOTAL_EFFECTS + 1;
}

void CustomTheme::ParameterUp() {
AnimationStation::options.customThemeCooldownTimeInMs = AnimationStation::options.customThemeCooldownTimeInMs + PRESS_COOLDOWN_INCREMENT;

if (AnimationStation::options.customThemeCooldownTimeInMs > PRESS_COOLDOWN_MAX) {
AnimationStation::options.customThemeCooldownTimeInMs = PRESS_COOLDOWN_MAX;
}
}

void CustomTheme::ParameterDown() {
AnimationStation::options.customThemeCooldownTimeInMs = AnimationStation::options.customThemeCooldownTimeInMs - PRESS_COOLDOWN_INCREMENT;

if (AnimationStation::options.customThemeCooldownTimeInMs > PRESS_COOLDOWN_MAX) {
AnimationStation::options.customThemeCooldownTimeInMs = PRESS_COOLDOWN_MIN;
}
}

RGB CustomTheme::BlendColor(RGB start, RGB end, uint32_t timeRemainingInMs) {
RGB result = ColorBlack;

if (timeRemainingInMs <= 0) {
return end;
}

float progress = 1.0f - (static_cast<float>(timeRemainingInMs) / static_cast<float>(coolDownTimeInMs));
if (progress < 0.0f) progress = 0.0f;
if (progress > 1.0f) progress = 1.0f;

result.r = static_cast<uint32_t>(static_cast<float>(start.r + (end.r - start.r) * progress));
result.g = static_cast<uint32_t>(static_cast<float>(start.g + (end.g - start.g) * progress));
result.b = static_cast<uint32_t>(static_cast<float>(start.b + (end.b - start.b) * progress));

return result;
}
13 changes: 0 additions & 13 deletions lib/AnimationStation/src/Effects/CustomTheme.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,11 @@ class CustomTheme : public Animation {

static bool HasTheme();
static void SetCustomTheme(std::map<uint32_t, RGB> customTheme);
virtual void UpdatePixels(std::vector<Pixel> pixels);
void Animate(RGB (&frame)[100]);
void ParameterUp();
void ParameterDown();
protected:
RGB defaultColor = ColorBlack;
static std::map<uint32_t, RGB> theme;

// timers per button
static std::map<uint32_t, int32_t> times;
static std::map<uint32_t, RGB> hitColor;

RGB BlendColor(RGB start, RGB end, uint32_t frame);

absolute_time_t lastUpdateTime = nil_time;

uint32_t coolDownTimeInMs = 1000;

};

#endif
Loading