]> git.donarmstrong.com Git - qmk_firmware.git/blob - users/drashna/rgb_stuff.c
[Docs] RGB Animation documentation on reducing memory footprint (#5813)
[qmk_firmware.git] / users / drashna / rgb_stuff.c
1 #include "drashna.h"
2 #include "rgb_stuff.h"
3 #include "eeprom.h"
4
5 #if defined(RGBLIGHT_ENABLE)
6 extern rgblight_config_t rgblight_config;
7 bool has_initialized;
8 #elif defined(RGB_MATRIX_ENABLE)
9 extern rgb_config_t rgb_matrix_config;
10 #endif
11
12 #ifdef RGBLIGHT_ENABLE
13 void rgblight_sethsv_default_helper(uint8_t index) {
14     rgblight_sethsv_at(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, index);
15 }
16 #endif // RGBLIGHT_ENABLE
17
18 #ifdef INDICATOR_LIGHTS
19 void set_rgb_indicators(uint8_t this_mod, uint8_t this_led, uint8_t this_osm) {
20     if (userspace_config.rgb_layer_change && biton32(layer_state) == 0) {
21         if ( (this_mod | this_osm) & MOD_MASK_SHIFT || this_led & (1<<USB_LED_CAPS_LOCK) ) {
22         #ifdef SHFT_LED1
23             rgblight_sethsv_at(120, 255, 255, SHFT_LED1);
24         #endif // SHFT_LED1
25         #ifdef SHFT_LED2
26             rgblight_sethsv_at(120, 255, 255, SHFT_LED2);
27         #endif // SHFT_LED2
28         } else {
29         #ifdef SHFT_LED1
30             rgblight_sethsv_default_helper(SHFT_LED1);
31         #endif // SHFT_LED1
32         #ifdef SHFT_LED2
33             rgblight_sethsv_default_helper(SHFT_LED2);
34         #endif // SHFT_LED2
35         }
36         if ( (this_mod | this_osm) & MOD_MASK_CTRL) {
37         #ifdef CTRL_LED1
38             rgblight_sethsv_at(0, 255, 255, CTRL_LED1);
39         #endif // CTRL_LED1
40         #ifdef CTRL_LED2
41             rgblight_sethsv_at(0, 255, 255, CTRL_LED2);
42         #endif // CTRL_LED2
43         } else {
44         #ifdef CTRL_LED1
45             rgblight_sethsv_default_helper(CTRL_LED1);
46         #endif // CTRL_LED1
47         #ifdef CTRL_LED2
48             rgblight_sethsv_default_helper(CTRL_LED2);
49         #endif // CTRL_LED2
50         }
51         if ( (this_mod | this_osm) & MOD_MASK_GUI) {
52         #ifdef GUI_LED1
53             rgblight_sethsv_at(51, 255, 255, GUI_LED1);
54         #endif // GUI_LED1
55         #ifdef GUI_LED2
56             rgblight_sethsv_at(51, 255, 255, GUI_LED2);
57         #endif // GUI_LED2
58         } else {
59         #ifdef GUI_LED1
60             rgblight_sethsv_default_helper(GUI_LED1);
61         #endif // GUI_LED1
62         #ifdef GUI_LED2
63             rgblight_sethsv_default_helper(GUI_LED2);
64         #endif // GUI_LED2
65         }
66         if ( (this_mod | this_osm) & MOD_MASK_ALT) {
67         #ifdef ALT_LED1
68             rgblight_sethsv_at(240, 255, 255, ALT_LED1);
69         #endif // ALT_LED1
70         #ifdef GUI_LED2
71             rgblight_sethsv_at(240, 255, 255, ALT_LED2);
72         #endif // GUI_LED2
73         } else {
74         #ifdef GUI_LED1
75             rgblight_sethsv_default_helper(ALT_LED1);
76         #endif // GUI_LED1
77         #ifdef GUI_LED2
78             rgblight_sethsv_default_helper(ALT_LED2);
79         #endif // GUI_LED2
80         }
81     }
82 }
83
84 void matrix_scan_indicator(void) {
85     if (has_initialized) {
86         set_rgb_indicators(get_mods(), host_keyboard_leds(), get_oneshot_mods());
87     }
88 }
89 #endif //INDICATOR_LIGHTS
90
91 #ifdef RGBLIGHT_TWINKLE
92 static rgblight_fadeout lights[RGBLED_NUM];
93
94 __attribute__ ((weak))
95 bool rgblight_twinkle_is_led_used_keymap(uint8_t index) { return false; }
96
97 bool rgblight_twinkle_is_led_used(uint8_t index) {
98     switch (index) {
99 #ifdef INDICATOR_LIGHTS
100 #ifdef SHFT_LED1
101         case SHFT_LED1:
102             return true;
103 #endif //SHFT_LED1
104 #ifdef SHFT_LED2
105         case SHFT_LED2:
106             return true;
107 #endif //SHFT_LED2
108 #ifdef CTRL_LED1
109         case CTRL_LED1:
110             return true;
111 #endif //CTRL_LED1
112 #ifdef CTRL_LED2
113         case CTRL_LED2:
114             return true;
115 #endif //CTRL_LED2
116 #ifdef GUI_LED1
117         case GUI_LED1:
118             return true;
119 #endif //GUI_LED1
120 #ifdef GUI_LED2
121         case GUI_LED2:
122             return true;
123 #endif //GUI_LED2
124 #ifdef ALT_LED1
125         case ALT_LED1:
126             return true;
127 #endif //ALT_LED1
128 #ifdef ALT_LED2
129         case ALT_LED2:
130             return true;
131 #endif //ALT_LED2
132 #endif //INDICATOR_LIGHTS
133         default:
134             return rgblight_twinkle_is_led_used_keymap(index);
135   }
136 }
137
138 void scan_rgblight_fadeout(void) { // Don't effing change this function .... rgblight_sethsv is supppppper intensive
139     bool litup = false;
140     for (uint8_t light_index = 0 ; light_index < RGBLED_NUM ; ++light_index ) {
141         if (lights[light_index].enabled && timer_elapsed(lights[light_index].timer) > 10) {
142         rgblight_fadeout *light = &lights[light_index];
143         litup = true;
144
145         if (light->life) {
146             light->life -= 1;
147             if (biton32(layer_state) == 0) {
148                 sethsv(light->hue + rand() % 0xF, 255, light->life, (LED_TYPE *)&led[light_index]);
149             }
150             light->timer = timer_read();
151         }
152         else {
153             if (light->enabled && biton32(layer_state) == 0) {
154                 rgblight_sethsv_default_helper(light_index);
155             }
156             litup = light->enabled = false;
157         }
158         }
159     }
160     if (litup && biton32(layer_state) == 0) {
161         rgblight_set();
162     }
163 }
164
165 void start_rgb_light(void) {
166
167     uint8_t indices[RGBLED_NUM];
168     uint8_t indices_count = 0;
169     uint8_t min_life = 0xFF;
170     uint8_t min_life_index = -1;
171     for (uint8_t index = 0 ; index < RGBLED_NUM ; ++index ) {
172       if (rgblight_twinkle_is_led_used(index)) { continue; }
173       if (lights[index].enabled) {
174         if (min_life_index == -1 ||
175           lights[index].life < min_life)
176         {
177           min_life = lights[index].life;
178           min_life_index = index;
179         }
180         continue;
181       }
182
183       indices[indices_count] = index;
184       ++indices_count;
185     }
186
187     uint8_t light_index;
188     if (!indices_count) {
189         light_index = min_life_index;
190     }
191     else {
192       light_index = indices[rand() % indices_count];
193     }
194
195     rgblight_fadeout *light = &lights[light_index];
196     light->enabled = true;
197     light->timer = timer_read();
198     light->life = 0xC0 + rand() % 0x40;
199
200     light->hue = rgblight_config.hue + (rand() % 0xB4) - 0x54;
201
202     rgblight_sethsv_at(light->hue, 255, light->life, light_index);
203 }
204 #endif
205
206
207 bool process_record_user_rgb(uint16_t keycode, keyrecord_t *record) {
208     if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
209         keycode = keycode & 0xFF;
210     }
211     switch (keycode) {
212 #ifdef RGBLIGHT_TWINKLE
213         case KC_A ... KC_SLASH:
214         case KC_F1 ... KC_F12:
215         case KC_INSERT ... KC_UP:
216         case KC_KP_SLASH ... KC_KP_DOT:
217         case KC_F13 ... KC_F24:
218         case KC_AUDIO_MUTE ... KC_MEDIA_REWIND:
219             if (record->event.pressed) { start_rgb_light(); }
220             return true; break;
221 #endif // RGBLIGHT_TWINKLE
222         case KC_RGB_T:  // This allows me to use underglow as layer indication, or as normal
223 #if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
224             if (record->event.pressed) {
225                 userspace_config.rgb_layer_change ^= 1;
226                 xprintf("rgblight layer change [EEPROM]: %u\n", userspace_config.rgb_layer_change);
227                 eeconfig_update_user(userspace_config.raw);
228                 if (userspace_config.rgb_layer_change) {
229                     layer_state_set(layer_state); // This is needed to immediately set the layer color (looks better)
230                 }
231             }
232 #endif // RGBLIGHT_ENABLE
233             return false; break;
234 #ifdef RGBLIGHT_ENABLE
235         case RGB_MODE_FORWARD ... RGB_MODE_GRADIENT: // quantum_keycodes.h L400 for definitions
236             if (record->event.pressed) { //This disables layer indication, as it's assumed that if you're changing this ... you want that disabled
237                 if (userspace_config.rgb_layer_change) {
238                     userspace_config.rgb_layer_change = false;
239                     xprintf("rgblight layer change [EEPROM]: %u\n", userspace_config.rgb_layer_change);
240                     eeconfig_update_user(userspace_config.raw);
241                 }
242             }
243             return true; break;
244 #endif // RGBLIGHT_ENABLE
245   }
246     return true;
247 }
248
249
250
251 void keyboard_post_init_rgb(void) {
252 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_STARTUP_ANIMATION)
253     if (userspace_config.rgb_layer_change) { rgblight_enable_noeeprom(); }
254     if (rgblight_config.enable) {
255         layer_state_set_user(layer_state);
256         uint16_t old_hue = rgblight_config.hue;
257         rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
258         for (uint16_t i = 255; i > 0; i--) {
259             rgblight_sethsv_noeeprom( ( i + old_hue) % 255, 255, 255);
260             matrix_scan();
261             wait_ms(10);
262         }
263     }
264 #endif
265     layer_state_set_user(layer_state);
266 }
267
268 void matrix_scan_rgb(void) {
269 #ifdef RGBLIGHT_TWINKLE
270     scan_rgblight_fadeout();
271 #endif // RGBLIGHT_ENABLE
272
273 #ifdef INDICATOR_LIGHTS
274     matrix_scan_indicator();
275 #endif
276
277 }
278
279
280 uint32_t layer_state_set_rgb(uint32_t state) {
281 #ifdef RGBLIGHT_ENABLE
282     if (userspace_config.rgb_layer_change) {
283         switch (biton32(state)) {
284             case _MACROS:
285                 rgblight_sethsv_noeeprom_orange();
286                 userspace_config.is_overwatch ? rgblight_mode_noeeprom(RGBLIGHT_MODE_SNAKE + 2) : rgblight_mode_noeeprom(RGBLIGHT_MODE_SNAKE + 3);
287                 break;
288             case _MEDIA:
289                 rgblight_sethsv_noeeprom_chartreuse();
290                 rgblight_mode_noeeprom(RGBLIGHT_MODE_KNIGHT + 1);
291                 break;
292             case _GAMEPAD:
293                 rgblight_sethsv_noeeprom_orange();
294                 rgblight_mode_noeeprom(RGBLIGHT_MODE_SNAKE + 2);
295                 break;
296             case _DIABLO:
297                 rgblight_sethsv_noeeprom_red();
298                 rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3);
299                 break;
300             case _RAISE:
301                 rgblight_sethsv_noeeprom_yellow();
302                 rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3);
303                 break;
304             case _LOWER:
305                 rgblight_sethsv_noeeprom_green();
306                 rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3);
307                 break;
308             case _ADJUST:
309                 rgblight_sethsv_noeeprom_red();
310                 rgblight_mode_noeeprom(RGBLIGHT_MODE_KNIGHT + 2);
311                 break;
312             default: //  for any other layers, or the default layer
313                 switch (biton32(default_layer_state)) {
314                     case _COLEMAK:
315                         rgblight_sethsv_noeeprom_magenta(); break;
316                     case _DVORAK:
317                         rgblight_sethsv_noeeprom_springgreen(); break;
318                     case _WORKMAN:
319                         rgblight_sethsv_noeeprom_goldenrod(); break;
320                     case _NORMAN:
321                         rgblight_sethsv_noeeprom_coral(); break;
322                     case _MALTRON:
323                         rgblight_sethsv_noeeprom_yellow(); break;
324                     case _EUCALYN:
325                         rgblight_sethsv_noeeprom_pink(); break;
326                     case _CARPLAX:
327                         rgblight_sethsv_noeeprom_blue(); break;
328                     default:
329                         rgblight_sethsv_noeeprom_cyan(); break;
330                 }
331                 biton32(state) == _MODS ? rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING) : rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT); // if _MODS layer is on, then breath to denote it
332                 break;
333         }
334     }
335 #endif // RGBLIGHT_ENABLE
336
337     return state;
338 }