Skip to content

Instantly share code, notes, and snippets.

@EndingCredits
Last active July 22, 2019 19:20
Show Gist options
  • Save EndingCredits/0355babc2aa8becb11c2ab8aada871ed to your computer and use it in GitHub Desktop.
Save EndingCredits/0355babc2aa8becb11c2ab8aada871ed to your computer and use it in GitHub Desktop.
Ripple effect for HS60 keyboard > https://i.imgur.com/GBUDbji.mp4
# See below for algorithm details
# https://web.archive.org/web/20160418004149/http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
// GRID_MAX refers to the maximum position of an LED via map_led_to_point
#define LED_GRID_MAX_Y 65
#define LED_GRID_MAX_X 255
// Number to shift right by to get to ripple grid
#define GRID_COARSE 4
// Width and height of ripple grid
#define R_HEIGHT (LED_GRID_MAX_Y>>GRID_COARSE)
#define R_WIDTH (LED_GRID_MAX_X>>GRID_COARSE)
// Wave persistence, higher = less decay
#define R_PERSISTENCE (7 - GRID_COARSE)
// Create ripple grid, which has two buffers
// uint16 to prevent overflow and to enable 'HDR'ness
uint16_t ripple_grid_a[R_WIDTH * R_HEIGHT];
uint16_t ripple_grid_b[R_WIDTH * R_HEIGHT];
uint16_t* ripple_grid_front;
uint16_t* ripple_grid_back;
void backlight_effect_keypress_ripples( bool initialize )
{
if (initialize) {
// Set buffers and zero-init them
ripple_grid_front = ripple_grid_a;
ripple_grid_back = ripple_grid_b;
for (uint16_t i = 0; i < R_WIDTH*R_HEIGHT; i++) {
ripple_grid_a[i] = 0;
ripple_grid_b[i] = 0;
}
}
Point point;
for ( int i=0; i<BACKLIGHT_LED_COUNT; i++ )
{
// Map LED to ripple grid
map_led_to_point( i, &point );
uint8_t x = MIN( point.x>>GRID_COARSE, R_WIDTH-1);
uint8_t y = MIN( point.y>>GRID_COARSE, R_HEIGHT-1);
// If keyhit, set 'height' to some value
if (g_key_hit[i]==1) {
ripple_grid_front[x + R_WIDTH*y] = 512;
}
// Get intensity from grid and clip value
uint8_t intensity = MIN(ripple_grid_back[x + R_WIDTH*y], 255);
// Set LED color from intenisty
HSV hsv = { .h = g_config.color_1.h,
.s = g_config.color_1.s,
.v = (g_config.brightness * intensity) / 255 };
RGB rgb = hsv_to_rgb( hsv );
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
}
// Ripples updates
if ( g_tick % (0x08 >> g_config.effect_speed) == 0) {
// For each cell in the ripple grid
for (uint8_t y = 0; y < R_HEIGHT; y++) {
for (uint8_t x = 0; x < R_WIDTH; x++) {
// Current cell
uint16_t* gridcell = &ripple_grid_back[x + R_WIDTH*y];
// Mapping for cells on edges to enable reflections
uint8_t x_p = (x == R_WIDTH-1) ? x - 1 : x + 1 ;
uint8_t x_n = (x == 0) ? x + 1 : x - 1 ;
uint8_t y_p = (y == R_HEIGHT-1) ? y - 1 : y + 1 ;
uint8_t y_n = (y == 0) ? y + 1 : y - 1 ;
// Apply filter
uint16_t neighbours = ripple_grid_front[x_p + R_WIDTH*y];
neighbours = neighbours + ripple_grid_front[x_n + R_WIDTH*y];
neighbours = neighbours + ripple_grid_front[x + R_WIDTH*y_p];
neighbours = neighbours + ripple_grid_front[x + R_WIDTH*y_n];
neighbours = neighbours / 2;
*gridcell = (neighbours > *gridcell) ? neighbours - *gridcell : 0;
// Decay value
*gridcell = *gridcell - (*gridcell >> R_PERSISTENCE);
}
}
// Swap buffers
uint16_t* temp = ripple_grid_front;
ripple_grid_front = ripple_grid_back;
ripple_grid_back = temp;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment