diff options
Diffstat (limited to 'users/xtonhasvim/fancylighting.c')
-rw-r--r-- | users/xtonhasvim/fancylighting.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/users/xtonhasvim/fancylighting.c b/users/xtonhasvim/fancylighting.c new file mode 100644 index 000000000..f4af5ec55 --- /dev/null +++ b/users/xtonhasvim/fancylighting.c @@ -0,0 +1,167 @@ + /* Copyright 2015-2017 Christon DeWan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef RGBLIGHT_ENABLE + +#include <math.h> + +#include "rgblight.h" +#include "color.h" +#include "fancylighting.h" + + +__attribute__ ((weak)) +void matrix_scan_keymap(void) { + // override me, if you want. + return; +} + +#define ABSDIFF(a,b) ((a)>(b)?(a)-(b):(b)-(a)) + +#define FADE_BACK_TIME 500 +#define BREATH_FIRE_TIME 1000 +#define ANIMATION_STEP_INTERVAL 20 +#define POWER_KEY_OFFSET (RGBLED_NUM / 2) +#define SPACE_OFFSET_MAX (RGBLED_NUM / 2) + + +uint16_t effect_start_timer = 0; +uint8_t user_rgb_mode = 0; +LED_TYPE shadowed_led[RGBLED_NUM] = {0}; + +void start_firey_return(void) { + user_rgb_mode = BREATH_FIRE; + effect_start_timer = timer_read(); + for(uint8_t i = 0; i < RGBLED_NUM; i++) { + shadowed_led[i] = led[i]; + } +} + +/** 0---max + * [___] + * [__/] + * [_/\] + * [/\_] + * [\__] + * [___] + **/ + +void set_color_for_offsets(uint16_t time_offset, uint16_t space_offset, uint8_t idx) { + float time_progress = (float)time_offset / BREATH_FIRE_TIME; + float space_progress = (float)space_offset / SPACE_OFFSET_MAX; + float progress = time_progress * 5.0 - space_progress; + if(progress > 1.0) { + progress -= 1.0; + progress /= 4.0; + progress = 1.0 - progress; + } + progress = fmax(0.0,progress); + progress *= progress; // squared! + + float alpha = (time_progress + 0.1) * 7.0 - space_progress; + alpha = fmin(1.0, alpha*alpha); + + LED_TYPE px[1] = {0}; + sethsv((uint16_t)(fmod(time_progress * 1.5 + space_progress,1.0)*360), 255, (uint8_t)(progress*255),&px[0]); + led[idx].r = alpha * px[0].r + ( 1.0 - alpha) * shadowed_led[idx].r; + led[idx].g = alpha * px[0].g + ( 1.0 - alpha) * shadowed_led[idx].g; + led[idx].b = alpha * px[0].b + ( 1.0 - alpha) * shadowed_led[idx].b; +} + +/** + * It's actually a rainbow: a fire curve didn't really look right. + * it's still cool, though! + */ +void rgb_mode_breath_fire(void) { + static uint16_t last_timer = 0; + if(!last_timer) last_timer = timer_read(); + uint16_t this_timer = timer_read(); + + // too soon. don't spam updates + if(this_timer - last_timer < ANIMATION_STEP_INTERVAL) return; + + uint16_t elapsed = this_timer - effect_start_timer; + + last_timer = this_timer; + if(elapsed >= BREATH_FIRE_TIME) { + // complete + user_rgb_mode = FADE_BACK; + effect_start_timer = this_timer; + } else { + // linear fade + for(uint16_t i = 0; i < RGBLED_NUM; i++) { + uint16_t space_offset = ABSDIFF(i,POWER_KEY_OFFSET); + if(space_offset > SPACE_OFFSET_MAX) space_offset = RGBLED_NUM - space_offset; + + set_color_for_offsets(elapsed, space_offset, i); + } + rgblight_set(); + } +} + +void rgb_mode_fade_back(void) { + static uint16_t last_timer = 0; + if(!last_timer) last_timer = timer_read(); + uint16_t this_timer = timer_read(); + + // too soon. don't spam updates + if(this_timer - last_timer < ANIMATION_STEP_INTERVAL) return; + + uint16_t elapsed = this_timer - effect_start_timer; + + last_timer = this_timer; + float progress = (float)elapsed / FADE_BACK_TIME; + progress = fmin(1.0,progress); + + for(uint8_t i = 0; i < RGBLED_NUM; i++) { + led[i].r = shadowed_led[i].r * progress; + led[i].g = shadowed_led[i].g * progress; + led[i].b = shadowed_led[i].b * progress; + } + rgblight_set(); + + if(elapsed >= FADE_BACK_TIME) user_rgb_mode = 0; +} + +/** called when layer state or vstate has changed */ +__attribute__ ((weak)) +void set_state_leds(void) { + return; +} + +void matrix_scan_user(void) { + static uint32_t last_layer = 0; + static uint32_t last_vstate = 0; + if(last_layer != layer_state || last_vstate != vstate) set_state_leds(); + last_layer = layer_state; + last_vstate = vstate; + + switch (user_rgb_mode) { + case BREATH_FIRE: + rgb_mode_breath_fire(); + break; + case FADE_BACK: + rgb_mode_fade_back(); + break; + } + matrix_scan_keymap(); +} + +#else + +void start_firey_return(void) {} + +#endif |