PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.3KB

  1. #ifndef MAGENTA_SQUARES_H__
  2. #define MAGENTA_SQUARES_H__
  3. #include <Arduino.h>
  4. #include "ILI9341_t3.h"
  5. #include "MathUtil.h"
  6. #include "BaseAnimation.h"
  7. const uint_fast8_t SQ_SPEED = 0x06;
  8. const uint_fast8_t SQ_SIZE = 16;
  9. const uint_fast8_t RIPPLE_SPEED_MIN = 0x05;
  10. const uint_fast8_t RIPPLE_SPEED_MAX = 0x0b;
  11. const uint_fast8_t RIPPLE_STROKE = 0x20;
  12. const float RIPPLE_AMP_LATCH = 1.5f;
  13. const float RIPPLE_AMP_DECAY = 0.01f;
  14. class MagentaSquares : public BaseAnimation {
  15. public:
  16. MagentaSquares() : BaseAnimation() {};
  17. void init( ILI9341_t3 tft );
  18. uint_fast16_t bgColor( void );
  19. String title();
  20. void perFrame( ILI9341_t3 tft, FrameParams frameParams );
  21. private:
  22. inline float distance2D( float w, float h );
  23. uint_fast8_t _step = 0;
  24. float _audioPeak = 0;
  25. uint_fast8_t _ripplePos = 0;
  26. uint_fast8_t _rippleSpeed = 0;
  27. uint_fast16_t _bgColor;
  28. uint_fast8_t sqAcross;
  29. uint_fast8_t sqDown;
  30. uint_fast8_t * radii;
  31. };
  32. inline float MagentaSquares::distance2D( float w, float h ) {
  33. return sqrt( w*w + h*h );
  34. }
  35. void MagentaSquares::init( ILI9341_t3 tft ) {
  36. uint_fast16_t w = tft.width();
  37. uint_fast16_t h = tft.height();
  38. sqAcross = w / SQ_SIZE;
  39. sqDown = h / SQ_SIZE;
  40. radii = (uint_fast8_t*)malloc( sqAcross * sqDown * sizeof(uint_fast8_t) );
  41. float w_2 = w / 2;
  42. float h_2 = h / 2;
  43. float distanceMult = (255.0-RIPPLE_STROKE) / distance2D( w_2, h_2 );
  44. for( uint_fast8_t i=0; i<sqAcross; i++ ) {
  45. for( uint_fast8_t j=0; j<sqDown; j++ ) {
  46. uint_fast8_t idx = j*sqAcross + i;
  47. radii[idx] = distanceMult * distance2D( ((float)i-sqAcross/2)*SQ_SIZE, ((float)j-sqDown/2)*SQ_SIZE );
  48. }
  49. }
  50. _bgColor = tft.color565( 0x88, 0, 0x88 );
  51. }
  52. uint_fast16_t MagentaSquares::bgColor( void ) {
  53. return _bgColor;
  54. }
  55. String MagentaSquares::title() {
  56. return "MagentaSquares";
  57. }
  58. void MagentaSquares::perFrame( ILI9341_t3 tft, FrameParams frameParams ) {
  59. //uint_fast16_t w = tft.width();
  60. //uint_fast16_t h = tft.height();
  61. // Trigger a new audio ripple?
  62. float amp_f = frameParams.audioMean; // range [0..1]
  63. if( amp_f > _audioPeak ) {
  64. _ripplePos = 0.0; // reset the ripple
  65. _rippleSpeed = lerp( RIPPLE_SPEED_MIN, RIPPLE_SPEED_MAX, min( 1.0, amp_f/_audioPeak - 1.0 ) );
  66. // The next peak must be ~1.5x louder than this one to trigger a ripple
  67. _audioPeak = amp_f * RIPPLE_AMP_LATCH;
  68. }
  69. for( uint_fast8_t i=0; i<sqAcross; i++ ) {
  70. for( uint_fast8_t j=0; j<sqDown; j++ ) {
  71. uint_fast16_t x = i * SQ_SIZE;
  72. uint_fast16_t y = j * SQ_SIZE;
  73. // Redraw black borders at the edge of each square.
  74. //tft.drawRect( x, y, SQ_SIZE, SQ_SIZE, 0x0 );
  75. uint_fast16_t clr;
  76. // If this square is within the ripple area, draw using white
  77. uint_fast8_t idx = j*sqAcross + i;
  78. uint_fast8_t radius = radii[idx];
  79. if( (radius < _ripplePos) && (_ripplePos < radius+RIPPLE_STROKE) ) {
  80. clr = tft.color565( 0xff, random(0x99,0xff), 0xff );
  81. } else {
  82. uint_fast8_t bright = (x+y+_step) & 0xff;
  83. clr = tft.color565( bright, 0, bright );
  84. }
  85. uint_fast8_t rando = random(SQ_SIZE>>1);
  86. tft.drawRect( x+rando, y+rando, SQ_SIZE-2*rando, SQ_SIZE-2*rando, clr );
  87. }
  88. }
  89. //delay(10);
  90. _step += SQ_SPEED * frameParams.timeMult;
  91. _audioPeak *= (1.0 - RIPPLE_AMP_DECAY * frameParams.timeMult);
  92. _ripplePos = min( 0xff, (uint_fast16_t)_ripplePos + _rippleSpeed * frameParams.timeMult );
  93. }
  94. #endif