visualizer.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. Copyright 2017 Fred Sundvik
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include "visualizer.h"
  15. #include "gfx.h"
  16. #include "math.h"
  17. #include "default_animations.h"
  18. #include "led_backlight_keyframes.h"
  19. #define NUM_ROWS LED_HEIGHT
  20. #define NUM_COLS LED_WIDTH
  21. #define ONESIDESCAN 10
  22. #define BOTHSIDESCAN 20
  23. #define FULL_ON LUMA2COLOR(255)
  24. #define THREE_QUARTER LUMA2COLOR(200)
  25. #define HALF_ON LUMA2COLOR(150)
  26. #define ONE_QUARTER LUMA2COLOR(50)
  27. #define CROSSFADE_TIME 500
  28. #define GRADIENT_TIME 3000
  29. bool led_backlight_keyframe_one_period_sweep(keyframe_animation_t* animation, visualizer_state_t* state);
  30. bool led_backlight_keyframe_half_period_sweep_to_on(keyframe_animation_t* animation, visualizer_state_t* state);
  31. bool led_backlight_keyframe_half_period_sweep_to_off(keyframe_animation_t* animation, visualizer_state_t* state);
  32. keyframe_animation_t Fade_in_all_leds = {
  33. .num_frames = 1,
  34. .loop = false,
  35. .frame_lengths = {
  36. CROSSFADE_TIME,
  37. },
  38. .frame_functions = {
  39. led_backlight_keyframe_fade_in_all,
  40. },
  41. };
  42. keyframe_animation_t decreasing_gradient = {
  43. .num_frames = 8,
  44. .loop = true,
  45. .frame_lengths = {
  46. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  47. 0, // mirror leds
  48. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  49. 0, // normal leds
  50. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  51. 0, // mirror leds
  52. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  53. 0, // normal leds
  54. },
  55. .frame_functions = {
  56. led_backlight_keyframe_one_period_sweep,
  57. led_backlight_keyframe_mirror_orientation,
  58. keyframe_no_operation,
  59. keyframe_no_operation,
  60. keyframe_no_operation,
  61. keyframe_no_operation,
  62. led_backlight_keyframe_one_period_sweep,
  63. led_backlight_keyframe_normal_orientation,
  64. },
  65. };
  66. static uint8_t off_on_off_gradient(float t, float index, float num) {
  67. const float two_pi = M_PI * 2.0f;
  68. float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
  69. float x = t * two_pi + normalized_index-M_PI;
  70. if((1*M_PI) < x && x < (3*M_PI))
  71. {
  72. float v = 0.5 * (cosf(x) + 1.0f);
  73. return (uint8_t)(255.0f * v);
  74. }
  75. else
  76. {
  77. return 0;
  78. }
  79. }
  80. static uint8_t off_on_gradient(float t, float index, float num) {
  81. const float two_pi = M_PI * 2.0f;
  82. float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
  83. float x = t * two_pi + normalized_index-M_PI;
  84. float v;
  85. if((1*M_PI) < x && x < (2*M_PI))
  86. {
  87. v = 0.5 * (cosf(x) + 1.0f);
  88. }
  89. else if(x >= (2*M_PI))
  90. {
  91. v = 1;
  92. }
  93. else
  94. {
  95. v = 0;
  96. }
  97. return (uint8_t)(255.0f * v);
  98. }
  99. static uint8_t on_off_gradient(float t, float index, float num) {
  100. const float two_pi = M_PI * 2.0f;
  101. float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
  102. float x = t * two_pi + normalized_index-M_PI;
  103. float v;
  104. if((2*M_PI) < x && x < (3*M_PI))
  105. {
  106. v = 0.5 * (cosf(x) + 1.0f);
  107. }
  108. else if(x >= (3*M_PI))
  109. {
  110. v = 0;
  111. }
  112. else
  113. {
  114. v = 1;
  115. }
  116. return (uint8_t)(255.0f * v);
  117. }
  118. bool led_backlight_keyframe_one_period_sweep(keyframe_animation_t* animation, visualizer_state_t* state) {
  119. (void)state;
  120. float frame_length = animation->frame_lengths[animation->current_frame];
  121. float current_pos = frame_length - animation->time_left_in_frame;
  122. float t = current_pos / frame_length;
  123. for (int i=0; i< NUM_COLS; i++) {
  124. uint8_t color = off_on_off_gradient(t*2, i, NUM_COLS);
  125. gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
  126. }
  127. return true;
  128. }
  129. bool led_backlight_keyframe_half_period_sweep_to_on(keyframe_animation_t* animation, visualizer_state_t* state) {
  130. (void)state;
  131. float frame_length = animation->frame_lengths[animation->current_frame];
  132. float current_pos = frame_length - animation->time_left_in_frame;
  133. float t = current_pos / frame_length;
  134. for (int i=0; i< NUM_COLS; i++) {
  135. uint8_t color = off_on_gradient(t*2, i, NUM_COLS);
  136. gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
  137. }
  138. return true;
  139. }
  140. bool led_backlight_keyframe_half_period_sweep_to_off(keyframe_animation_t* animation, visualizer_state_t* state) {
  141. (void)state;
  142. float frame_length = animation->frame_lengths[animation->current_frame];
  143. float current_pos = frame_length - animation->time_left_in_frame;
  144. float t = current_pos / frame_length;
  145. for (int i=0; i< NUM_COLS; i++) {
  146. uint8_t color = on_off_gradient(t*2, i, NUM_COLS);
  147. gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
  148. }
  149. return true;
  150. }
  151. /*
  152. +---+---+---+---+---+---+---+---+---+---+---+---+---+---+-------+
  153. | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | phase |
  154. +---+---+---+---+---+---+---+---+---+---+---+---+---+---+-------+
  155. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
  156. | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
  157. | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 |
  158. | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
  159. | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
  160. | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 |
  161. | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 |
  162. | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 |
  163. | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 8 |
  164. | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 9 |
  165. | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 0 | 10 |
  166. | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 0 | 11 |
  167. | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 0 | 12 |
  168. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 13 |
  169. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 14 |
  170. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 15 |
  171. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 4 | 16 |
  172. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 17 |
  173. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 18 |
  174. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 19 |
  175. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 20 |
  176. +---+---+---+---+---+---+---+---+---+---+---+---+---+---+-------+
  177. */
  178. #ifdef MASTER_IS_ON_RIGHT /*right side*/
  179. keyframe_animation_t sweep_on_sweep_off_left_and_right = {
  180. .num_frames = 12,
  181. .loop = true,
  182. .frame_lengths = {
  183. 0,
  184. 1,
  185. gfxMillisecondsToTicks(GRADIENT_TIME), // left on
  186. gfxMillisecondsToTicks(GRADIENT_TIME), // right on
  187. gfxMillisecondsToTicks(GRADIENT_TIME), // left off
  188. gfxMillisecondsToTicks(GRADIENT_TIME), // right off
  189. 0, // mirror leds
  190. gfxMillisecondsToTicks(GRADIENT_TIME), // right on
  191. gfxMillisecondsToTicks(GRADIENT_TIME), // left on
  192. gfxMillisecondsToTicks(GRADIENT_TIME), // right off
  193. gfxMillisecondsToTicks(GRADIENT_TIME), // left off
  194. 0, // normal leds
  195. },
  196. .frame_functions = {
  197. led_backlight_keyframe_mirror_orientation,
  198. led_backlight_keyframe_fade_out_all,
  199. keyframe_no_operation,
  200. led_backlight_keyframe_half_period_sweep_to_on,
  201. keyframe_no_operation,
  202. led_backlight_keyframe_half_period_sweep_to_off,
  203. led_backlight_keyframe_normal_orientation,
  204. led_backlight_keyframe_half_period_sweep_to_on,
  205. keyframe_no_operation,
  206. led_backlight_keyframe_half_period_sweep_to_off,
  207. keyframe_no_operation,
  208. led_backlight_keyframe_mirror_orientation,
  209. },
  210. };
  211. keyframe_animation_t both_sides_fade_across = {
  212. .num_frames = 10,
  213. .loop = true,
  214. .frame_lengths = {
  215. 0,
  216. 1,
  217. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  218. 0, // mirror leds
  219. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  220. 0, // normal leds
  221. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  222. 0, // mirror leds
  223. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  224. 0, // normal leds
  225. },
  226. .frame_functions = {
  227. led_backlight_keyframe_mirror_orientation,
  228. led_backlight_keyframe_fade_out_all,
  229. keyframe_no_operation,
  230. keyframe_no_operation,
  231. led_backlight_keyframe_one_period_sweep,
  232. led_backlight_keyframe_normal_orientation,
  233. led_backlight_keyframe_one_period_sweep,
  234. led_backlight_keyframe_mirror_orientation,
  235. keyframe_no_operation,
  236. keyframe_no_operation,
  237. },
  238. };
  239. #else /*left side*/
  240. keyframe_animation_t sweep_on_sweep_off_left_and_right = {
  241. .num_frames = 10,
  242. .loop = true,
  243. .frame_lengths = {
  244. gfxMillisecondsToTicks(GRADIENT_TIME), // left on
  245. gfxMillisecondsToTicks(GRADIENT_TIME), // right on
  246. gfxMillisecondsToTicks(GRADIENT_TIME), // left off
  247. gfxMillisecondsToTicks(GRADIENT_TIME), // right off
  248. 0, // mirror leds
  249. gfxMillisecondsToTicks(GRADIENT_TIME), // right on
  250. gfxMillisecondsToTicks(GRADIENT_TIME), // left on
  251. gfxMillisecondsToTicks(GRADIENT_TIME), // right off
  252. gfxMillisecondsToTicks(GRADIENT_TIME), // left off
  253. 0, // normal leds
  254. },
  255. .frame_functions = {
  256. led_backlight_keyframe_half_period_sweep_to_on,
  257. keyframe_no_operation,
  258. led_backlight_keyframe_half_period_sweep_to_off,
  259. keyframe_no_operation,
  260. led_backlight_keyframe_mirror_orientation,
  261. keyframe_no_operation,
  262. led_backlight_keyframe_half_period_sweep_to_on,
  263. keyframe_no_operation,
  264. led_backlight_keyframe_half_period_sweep_to_off,
  265. led_backlight_keyframe_normal_orientation,
  266. },
  267. };
  268. keyframe_animation_t both_sides_fade_across = {
  269. .num_frames = 8,
  270. .loop = true,
  271. .frame_lengths = {
  272. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  273. 0, // mirror leds
  274. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  275. 0, // normal leds
  276. gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
  277. 0, // mirror leds
  278. gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
  279. 0, // normal leds
  280. },
  281. .frame_functions = {
  282. led_backlight_keyframe_one_period_sweep,
  283. led_backlight_keyframe_mirror_orientation,
  284. keyframe_no_operation,
  285. keyframe_no_operation,
  286. keyframe_no_operation,
  287. keyframe_no_operation,
  288. led_backlight_keyframe_one_period_sweep,
  289. led_backlight_keyframe_normal_orientation,
  290. },
  291. };
  292. #endif
  293. #define RED 0
  294. #define ORANGE 21
  295. #define YELLOW 42
  296. #define SPRING_GREEN 64
  297. #define GREEN 85
  298. #define TURQUOISE 107
  299. #define CYAN 127
  300. #define OCEAN 149
  301. #define BLUE 170
  302. #define VIOLET 192
  303. #define MAGENTA 212
  304. #define RASPBERRY 234
  305. // This function should be implemented by the keymap visualizer
  306. // Don't change anything else than state->target_lcd_color and state->layer_text as that's the only thing
  307. // that the simple_visualizer assumes that you are updating
  308. // Also make sure that the buffer passed to state->layer_text remains valid until the previous animation is
  309. // stopped. This can be done by either double buffering it or by using constant strings
  310. static void get_visualizer_layer_and_color(visualizer_state_t* state) {
  311. uint8_t saturation = 255;
  312. /* if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) {
  313. saturation = 255;
  314. } */
  315. if (state->status.layer & 0x400) {
  316. state->target_lcd_color = LCD_COLOR(OCEAN, saturation, 0xFF);
  317. state->layer_text = "STENOGRAPHY";
  318. }
  319. else if (state->status.layer & 0x200) {
  320. state->target_lcd_color = LCD_COLOR(GREEN, saturation, 0xFF);
  321. state->layer_text = "FUNCTION";
  322. }
  323. else if (state->status.layer & 0x100) {
  324. state->target_lcd_color = LCD_COLOR(MAGENTA, saturation, 0xFF);
  325. state->layer_text = "Shortcuts Layer";
  326. stop_keyframe_animation(&sweep_on_sweep_off_left_and_right);
  327. start_keyframe_animation(&led_test_animation);
  328. }
  329. else if (state->status.layer & 0x80) {
  330. state->target_lcd_color = LCD_COLOR(VIOLET, saturation, 0xFF);
  331. state->layer_text = "Plover";
  332. }
  333. else if (state->status.layer & 0x40) {
  334. state->target_lcd_color = LCD_COLOR(RASPBERRY, saturation, 0xFF);
  335. state->layer_text = "Mirrored Symbols";
  336. }
  337. else if (state->status.layer & 0x20) {
  338. state->target_lcd_color = LCD_COLOR(RED, saturation, 0xFF);
  339. state->layer_text = "Symbols";
  340. }
  341. else if (state->status.layer & 0x8) {
  342. state->target_lcd_color = LCD_COLOR(OCEAN, saturation, 0xFF);
  343. state->layer_text = "Mirrored Dvorak";
  344. }
  345. else if (state->status.layer & 0x4) {
  346. state->target_lcd_color = LCD_COLOR(BLUE, saturation, 0xFF);
  347. state->layer_text = "Dvorak";
  348. stop_keyframe_animation(&led_test_animation);
  349. start_keyframe_animation(&sweep_on_sweep_off_left_and_right);
  350. }
  351. else if (state->status.layer & 0x2) {
  352. state->target_lcd_color = LCD_COLOR(ORANGE, saturation, 0xFF);
  353. state->layer_text = "Mirrored Qwerty";
  354. }
  355. else {
  356. state->target_lcd_color = LCD_COLOR(YELLOW, saturation, 0xFF);
  357. state->layer_text = "Qwerty";
  358. stop_keyframe_animation(&led_test_animation);
  359. start_keyframe_animation(&Fade_in_all_leds);
  360. }
  361. }