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.

168 line
5.6KB

  1. #ifndef SPHERE_3D_H__
  2. #define SPHERE_3D_H__
  3. #include <Arduino.h>
  4. #include "ILI9341_t3.h"
  5. #include "MathUtil.h"
  6. #include "BaseAnimation.h"
  7. const float SPHERE_3D_ROTATE_SPEED = 0.005f;
  8. const float SPHERE_3D_TILT_SPEED = 2.0f;
  9. const float SPHERE_3D_TILT_AMOUNT = 0.4f;
  10. // 3D render
  11. const float SPHERE_DISTANCE = 2.5f;
  12. const float SPHERE_OUTER_MULT = 1.414f; // spike size
  13. class Sphere3D : public BaseAnimation {
  14. public:
  15. Sphere3D() : BaseAnimation() {};
  16. void init( ILI9341_t3 tft );
  17. uint_fast16_t bgColor( void );
  18. String title();
  19. void perFrame( ILI9341_t3 tft, FrameParams frameParams );
  20. private:
  21. void _drawLine( ILI9341_t3 tft, float cosTilt, float sinTilt, float x, float y, float z, uint_fast16_t w_2, uint_fast16_t h_2, uint_fast16_t color );
  22. float _rotatePhase = 0;
  23. uint_fast16_t _baseCircSize = 0;
  24. uint_fast16_t _circStep = 0;
  25. uint_fast8_t _sparkle = 0;
  26. uint_fast16_t _bgColor;
  27. };
  28. void Sphere3D::init( ILI9341_t3 tft ) {
  29. uint_fast16_t w = tft.width();
  30. uint_fast16_t h = tft.height();
  31. //_bgColor = tft.color565( 0, 0x44, 0x44 ); // Only looks good in low light :P
  32. _bgColor = tft.color565( 0, 0, 0 );
  33. Point16 sphereTopOnScreen = xyz2screen( 0, -1.0f, SPHERE_DISTANCE, (w>>1), (h>>1) );
  34. _baseCircSize = (h/2) - sphereTopOnScreen.y + 1;
  35. }
  36. uint_fast16_t Sphere3D::bgColor(){
  37. return _bgColor;
  38. }
  39. String Sphere3D::title() {
  40. return "Sphere3D";
  41. }
  42. void Sphere3D::_drawLine( ILI9341_t3 tft, float cosTilt, float sinTilt, float x, float y, float z, uint_fast16_t w_2, uint_fast16_t h_2, uint_fast16_t color ) {
  43. // Tilt!
  44. float tempY = y;
  45. y = tempY*cosTilt + z*sinTilt;
  46. z = z*cosTilt - tempY*sinTilt;
  47. Point16 innerPt = xyz2screen( x, y, z+SPHERE_DISTANCE, w_2, h_2 );
  48. Point16 outerPt = xyz2screen( x*SPHERE_OUTER_MULT, y*SPHERE_OUTER_MULT, z*SPHERE_OUTER_MULT + SPHERE_DISTANCE, w_2, h_2 );
  49. tft.drawLine( innerPt.x, innerPt.y, outerPt.x, outerPt.y, color );
  50. // Just for kicks... Let's draw some circumference lines
  51. const float T_BAR_RADIUS = 0.1f;
  52. Point16 p0 = xyz2screen( x-z*T_BAR_RADIUS, y, z+x*T_BAR_RADIUS + SPHERE_DISTANCE, w_2, h_2 );
  53. Point16 p1 = xyz2screen( x+z*T_BAR_RADIUS, y, z-x*T_BAR_RADIUS + SPHERE_DISTANCE, w_2, h_2 );
  54. tft.drawLine( p0.x, p0.y, p1.x, p1.y, color );
  55. }
  56. void Sphere3D::perFrame( ILI9341_t3 tft, FrameParams frameParams ) {
  57. uint_fast16_t w = (uint_fast16_t)tft.width();
  58. uint_fast16_t h = (uint_fast16_t)tft.height();
  59. uint_fast16_t w_2 = (w>>1);
  60. uint_fast16_t h_2 = (h>>1);
  61. float oldPhase = _rotatePhase;
  62. _rotatePhase += frameParams.timeMult * SPHERE_3D_ROTATE_SPEED;
  63. _sparkle = max( (frameParams.audioPeak >> 1), _sparkle * (1.0f-(frameParams.timeMult*0.02f)) );
  64. uint_fast16_t erase = _bgColor;
  65. float x, y, z, sinLat;
  66. float oldTilt = -sin( oldPhase * SPHERE_3D_TILT_SPEED ) * SPHERE_3D_TILT_AMOUNT;
  67. float oldCosTilt = cos( oldTilt );
  68. float oldSinTilt = sin( oldTilt );
  69. float tilt = -sin( _rotatePhase * SPHERE_3D_TILT_SPEED ) * SPHERE_3D_TILT_AMOUNT;
  70. float cosTilt = cos( tilt );
  71. float sinTilt = sin( tilt );
  72. // Rotating sphere yo
  73. for( float lon=0.0f; lon<(M_PI*0.5f); lon+=(M_PI*0.125f) ) { // longitude (around). Only 1/4 of sphere circumference.
  74. for( float lat=(M_PI*0.0625f); lat<(M_PI*0.5f); lat+=(M_PI*0.125f) ) { // latitude (up & down). Only 1/2 of sphere height.
  75. // Erase the old line here
  76. x = cos( oldPhase + lon );
  77. z = sin( oldPhase + lon );
  78. y = cos( lat );
  79. sinLat = sin( lat );
  80. x *= sinLat;
  81. z *= sinLat;
  82. // We can swap & negate x,y,z to draw at least 8 lines without recomputing cos & sin values etc
  83. _drawLine( tft, oldCosTilt, oldSinTilt, x, y, z, w_2, h_2, erase );
  84. _drawLine( tft, oldCosTilt, oldSinTilt, -x, y, -z, w_2, h_2, erase );
  85. _drawLine( tft, oldCosTilt, oldSinTilt, -z, y, x, w_2, h_2, erase );
  86. _drawLine( tft, oldCosTilt, oldSinTilt, z, y, -x, w_2, h_2, erase );
  87. // Draw the other hemisphere
  88. _drawLine( tft, oldCosTilt, oldSinTilt, x, -y, z, w_2, h_2, erase );
  89. _drawLine( tft, oldCosTilt, oldSinTilt, -x, -y, -z, w_2, h_2, erase );
  90. _drawLine( tft, oldCosTilt, oldSinTilt, -z, -y, x, w_2, h_2, erase );
  91. _drawLine( tft, oldCosTilt, oldSinTilt, z, -y, -x, w_2, h_2, erase );
  92. // Now, draw the new lines
  93. uint_fast16_t color = tft.color565(
  94. random( _sparkle>>1, _sparkle ),
  95. random( _sparkle>>1, _sparkle ),
  96. 0xff
  97. );
  98. x = cos( _rotatePhase + lon );
  99. z = sin( _rotatePhase + lon );
  100. // Now we need the y (up & down), then normalize x & z to create a normalized 3D vector (length == 1.0)
  101. y = cos( lat );
  102. sinLat = sin( lat );
  103. x *= sinLat;
  104. z *= sinLat;
  105. // We can swap & negate x,y,z to draw at least 8 lines without recomputing cos & sin values etc
  106. _drawLine( tft, cosTilt, sinTilt, x, y, z, w_2, h_2, color );
  107. _drawLine( tft, cosTilt, sinTilt, -x, y, -z, w_2, h_2, color );
  108. _drawLine( tft, cosTilt, sinTilt, -z, y, x, w_2, h_2, color );
  109. _drawLine( tft, cosTilt, sinTilt, z, y, -x, w_2, h_2, color );
  110. // Draw the other hemisphere
  111. _drawLine( tft, cosTilt, sinTilt, x, -y, z, w_2, h_2, color );
  112. _drawLine( tft, cosTilt, sinTilt, -x, -y, -z, w_2, h_2, color );
  113. _drawLine( tft, cosTilt, sinTilt, -z, -y, x, w_2, h_2, color );
  114. _drawLine( tft, cosTilt, sinTilt, z, -y, -x, w_2, h_2, color );
  115. }
  116. }
  117. const uint_fast8_t RADIATION_PX = 12;
  118. _circStep += random(1,4);
  119. if( _circStep > RADIATION_PX ) _circStep -= RADIATION_PX;
  120. float brightAmt = ((frameParams.audioMean + 1.0f) * 0.5f); // 0.5...1
  121. uint_fast8_t bright = (0xff/RADIATION_PX) * brightAmt;
  122. uint_fast16_t radiationColor = tft.color565( 0, random((RADIATION_PX-_circStep)*(bright>>1)), random((RADIATION_PX-_circStep)*bright) ) | _bgColor;
  123. tft.drawCircle( w_2, h_2, _baseCircSize + _circStep, radiationColor );
  124. }
  125. #endif