Advertisement
Guest User

Untitled

a guest
Mar 6th, 2025
2,232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.49 KB | None | 0 0
  1. #include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
  2. #include <math.h>
  3.  
  4. // ===== Panel Configuration =====
  5. const int panelResX = 64;
  6. const int panelResY = 64;
  7. const int panel_chain = 2;
  8. const int WIDTH = panelResX * panel_chain; // 128
  9. const int HEIGHT = panelResY; // 64
  10. const int CENTER_X = WIDTH / 2;
  11. const int CENTER_Y = HEIGHT / 2;
  12.  
  13. MatrixPanel_I2S_DMA *matrix = nullptr;
  14.  
  15. // ===== Two Swirls (Galaxies) =====
  16. #define NUM_STARS 100
  17. #define NUM_ARMS 3
  18. #define MAX_RADIUS 40.0f
  19. #define THICKNESS 6.0f
  20.  
  21. // Each swirl star
  22. struct SwirlStar {
  23. float baseX, baseY, baseZ;
  24. uint8_t baseHue;
  25. };
  26.  
  27. // We'll have two sets of swirl stars
  28. SwirlStar swirlA[NUM_STARS];
  29. SwirlStar swirlB[NUM_STARS];
  30.  
  31. // Initial swirl center positions
  32. float swirlACenterX_init = -30.0f;
  33. float swirlACenterY_init = 0.0f;
  34. float swirlBCenterX_init = +30.0f;
  35. float swirlBCenterY_init = 0.0f;
  36.  
  37. // Current swirl center positions (they orbit)
  38. float swirlACenterX, swirlACenterY;
  39. float swirlBCenterX, swirlBCenterY;
  40.  
  41. // Rotation angles for each swirl
  42. float rotAx = 0.0f, rotAy = 0.0f, rotAz = 0.0f;
  43. float rotBx = 0.0f, rotBy = 0.0f, rotBz = 0.0f;
  44.  
  45. // Speeds for each swirl
  46. float speedAx = 0.01f, speedAy = 0.015f, speedAz = 0.008f;
  47. float speedBx = 0.012f, speedBy = 0.013f, speedBz = 0.01f;
  48.  
  49. // Warp effect
  50. const float WARP_MAX_ANGLE = M_PI / 9;
  51. const uint32_t WARP_PERIOD_MS = 10000;
  52.  
  53. // Color cycle
  54. const uint32_t COLOR_CYCLE_MS = 8000;
  55.  
  56. // Fade factor for trails
  57. const uint8_t FADE_FACTOR = 230;
  58.  
  59. // We'll orbit the swirl centers around each other
  60. float swirlOrbitRadius = 20.0f;
  61. float swirlOrbitAngle = 0.0f;
  62. float swirlOrbitSpeed = 0.003f;
  63.  
  64. // ---------- HSV to RGB Utility ----------
  65. void hsvToRgb(uint8_t h, uint8_t s, uint8_t v,
  66. uint8_t &r, uint8_t &g, uint8_t &b) {
  67. uint8_t region = h / 43;
  68. uint8_t remainder = (h - region * 43) * 6;
  69. uint8_t p = (v * (255 - s)) / 255;
  70. uint8_t q = (v * (255 - ((s * remainder) / 255))) / 255;
  71. uint8_t t = (v * (255 - ((s * (255 - remainder)) / 255))) / 255;
  72. switch (region) {
  73. case 0: r = v; g = t; b = p; break;
  74. case 1: r = q; g = v; b = p; break;
  75. case 2: r = p; g = v; b = t; break;
  76. case 3: r = p; g = q; b = v; break;
  77. case 4: r = t; g = p; b = v; break;
  78. default: r = v; g = p; b = q; break;
  79. }
  80. }
  81.  
  82. // ========== Fade Buffer ==========
  83. static uint8_t frameBuf[HEIGHT][WIDTH][3];
  84.  
  85. // ========== Explosion State ==========
  86. bool inExplosion = false; // are we currently in an explosion?
  87. uint32_t explosionStartTime = 0; // when explosion started
  88. const uint32_t EXPLOSION_DURATION = 2000; // 2 seconds
  89. float collisionX = 0, collisionY = 0; // where collision happened
  90.  
  91. // ========== Spiral Generation ==========
  92. void generateSpiral(SwirlStar *swirl) {
  93. for (int i = 0; i < NUM_STARS; i++) {
  94. int arm = random(NUM_ARMS);
  95. float r = sqrtf((float)random(0, 10001) / 10000.0f) * MAX_RADIUS;
  96. float baseArmAngle = ((float)arm / NUM_ARMS) * 2.0f * M_PI;
  97. float twist = r * 0.8f;
  98. float noise = (((float)random(-100, 101)) / 1000.0f) * M_PI;
  99. float angle = baseArmAngle + twist + noise;
  100. float x = r * cosf(angle);
  101. float y = r * sinf(angle);
  102. float z = (((float)random(-100, 101)) / 100.0f) * (THICKNESS / 2.0f);
  103. swirl[i].baseX = x;
  104. swirl[i].baseY = y;
  105. swirl[i].baseZ = z;
  106. swirl[i].baseHue = (uint8_t)random(0, 256);
  107. }
  108. }
  109.  
  110. void setup() {
  111. // Panel config
  112. HUB75_I2S_CFG mxconfig(panelResX, panelResY, panel_chain);
  113. mxconfig.double_buff = true;
  114. mxconfig.gpio.e = 18;
  115. mxconfig.clkphase = false;
  116. matrix = new MatrixPanel_I2S_DMA(mxconfig);
  117. matrix->begin();
  118. matrix->setBrightness8(200);
  119. matrix->fillScreen(matrix->color565(0, 0, 0));
  120.  
  121. // Clear fade buffer
  122. for (int y = 0; y < HEIGHT; y++) {
  123. for (int x = 0; x < WIDTH; x++) {
  124. frameBuf[y][x][0] = 0;
  125. frameBuf[y][x][1] = 0;
  126. frameBuf[y][x][2] = 0;
  127. }
  128. }
  129.  
  130. randomSeed(millis());
  131. generateSpiral(swirlA);
  132. generateSpiral(swirlB);
  133.  
  134. // set initial swirl centers
  135. swirlACenterX = swirlACenterX_init;
  136. swirlACenterY = swirlACenterY_init;
  137. swirlBCenterX = swirlBCenterX_init;
  138. swirlBCenterY = swirlBCenterY_init;
  139. }
  140.  
  141. // Draw swirl function
  142. void drawSwirl(SwirlStar *swirl, float centerX, float centerY,
  143. float rotX, float rotY, float rotZ,
  144. float tiltAngle, uint8_t hueOffset)
  145. {
  146. for (int i = 0; i < NUM_STARS; i++) {
  147. float x = swirl[i].baseX;
  148. float y = swirl[i].baseY;
  149. float z = swirl[i].baseZ;
  150.  
  151. // Rotation around X
  152. float y1 = y * cosf(rotX) - z * sinf(rotX);
  153. float z1 = y * sinf(rotX) + z * cosf(rotX);
  154. // Rotation around Y
  155. float x2 = x * cosf(rotY) + z1 * sinf(rotY);
  156. float z2 = -x * sinf(rotY) + z1 * cosf(rotY);
  157. // Rotation around Z
  158. float x3 = x2 * cosf(rotZ) - y1 * sinf(rotZ);
  159. float y3 = x2 * sinf(rotZ) + y1 * cosf(rotZ);
  160. float z3 = z2;
  161.  
  162. // Warp tilt around X
  163. float yw = y3 * cosf(tiltAngle) - z3 * sinf(tiltAngle);
  164. float zw = y3 * sinf(tiltAngle) + z3 * cosf(tiltAngle);
  165.  
  166. // Translate swirl center in XY, keep Z
  167. float finalX = x3 + centerX;
  168. float finalY = yw + centerY;
  169. float finalZ = zw;
  170.  
  171. // Perspective
  172. float cameraDist = 100.0f;
  173. float depth = cameraDist - finalZ;
  174. if (depth < 1.0f) continue;
  175. float scale = cameraDist / depth;
  176. float projX = finalX * scale;
  177. float projY = finalY * scale;
  178.  
  179. int screenX = (int)(CENTER_X + projX);
  180. int screenY = (int)(CENTER_Y - projY);
  181. if (screenX < 0 || screenX >= WIDTH || screenY < 0 || screenY >= HEIGHT)
  182. continue;
  183.  
  184. // Outer => faster => brighter
  185. float baseRadius = sqrtf(x*x + y*y);
  186. uint8_t brightness = (uint8_t)fmin(255.0f * (baseRadius / MAX_RADIUS), 255.0f);
  187.  
  188. // Hue shift
  189. uint8_t hue = swirl[i].baseHue + hueOffset;
  190. uint8_t rr, gg, bb;
  191. hsvToRgb(hue, 255, brightness, rr, gg, bb);
  192.  
  193. matrix->drawPixel(screenX, screenY, matrix->color565(rr, gg, bb));
  194. frameBuf[screenY][screenX][0] = rr;
  195. frameBuf[screenY][screenX][1] = gg;
  196. frameBuf[screenY][screenX][2] = bb;
  197. }
  198. }
  199.  
  200. // Explosion drawing
  201. void drawExplosion(uint32_t now, float cx, float cy) {
  202. // Explosion progress = 0..1
  203. float elapsed = (now - explosionStartTime);
  204. float progress = elapsed / (float)EXPLOSION_DURATION;
  205. if (progress>1.0f) progress=1.0f;
  206.  
  207. // The radius of the blast grows from 0.. ~1.5*screen width
  208. float maxR = sqrtf((float)(WIDTH*WIDTH + HEIGHT*HEIGHT)) * 0.75f;
  209. float blastRadius = maxR * progress;
  210.  
  211. // The color might fade or shift
  212. // Let's do a bright white with a slight red tint
  213. // that dims as it expands
  214. int baseVal = (int)(255 * (1.0f - progress));
  215. if (baseVal<0) baseVal=0;
  216. uint8_t rr = 255, gg = (uint8_t)baseVal, bb = (uint8_t)baseVal/2;
  217.  
  218. // Convert center to screen coords
  219. // Because swirl centers are in the swirl's local space,
  220. // we might just treat them as screen coords. Or we do
  221. // perspective if we want. For simplicity, treat them
  222. // as 2D screen coords for the explosion center.
  223. int scx = (int)(CENTER_X + cx);
  224. int scy = (int)(CENTER_Y - cy);
  225.  
  226. // Draw a radial fill in 2D
  227. for (int y=0; y<HEIGHT; y++) {
  228. for (int x=0; x<WIDTH; x++) {
  229. int dx = x - scx;
  230. int dy = y - scy;
  231. float dist = sqrtf(dx*dx + dy*dy);
  232. if (dist <= blastRadius) {
  233. // fraction how close to the edge
  234. float f = 1.0f - (dist/blastRadius);
  235. int cval = (int)(baseVal + (255-baseVal)*f);
  236. if (cval>255) cval=255;
  237. // store
  238. uint8_t oldR = frameBuf[y][x][0];
  239. uint8_t oldG = frameBuf[y][x][1];
  240. uint8_t oldB = frameBuf[y][x][2];
  241. // blend or just overwrite? let's do overwrite for dramatic effect
  242. uint8_t newR = (uint8_t)cval;
  243. uint8_t newG = (uint8_t)(cval/4);
  244. uint8_t newB = (uint8_t)(cval/6);
  245. // write
  246. frameBuf[y][x][0] = newR;
  247. frameBuf[y][x][1] = newG;
  248. frameBuf[y][x][2] = newB;
  249. matrix->drawPixel(x,y, matrix->color565(newR,newG,newB));
  250. }
  251. }
  252. }
  253. }
  254.  
  255. // Reset the entire scene after explosion
  256. void resetScene() {
  257. // Regenerate swirl star positions
  258. generateSpiral(swirlA);
  259. generateSpiral(swirlB);
  260.  
  261. // reset swirl angles
  262. rotAx = rotAy = rotAz = 0.0f;
  263. rotBx = rotBy = rotBz = 0.0f;
  264. swirlOrbitAngle = 0.0f;
  265.  
  266. // reset swirl center positions
  267. swirlACenterX = swirlACenterX_init;
  268. swirlACenterY = swirlACenterY_init;
  269. swirlBCenterX = swirlBCenterX_init;
  270. swirlBCenterY = swirlBCenterY_init;
  271.  
  272. // clear fade buffer
  273. for (int y=0; y<HEIGHT; y++){
  274. for (int x=0; x<WIDTH; x++){
  275. frameBuf[y][x][0] = 0;
  276. frameBuf[y][x][1] = 0;
  277. frameBuf[y][x][2] = 0;
  278. matrix->drawPixel(x,y, 0); // black
  279. }
  280. }
  281. matrix->flipDMABuffer();
  282. }
  283.  
  284. void loop() {
  285. uint32_t now = millis();
  286.  
  287. // 1) Fade old frame
  288. for (int y = 0; y < HEIGHT; y++) {
  289. for (int x = 0; x < WIDTH; x++) {
  290. uint8_t r = frameBuf[y][x][0];
  291. uint8_t g = frameBuf[y][x][1];
  292. uint8_t b = frameBuf[y][x][2];
  293. r = (r * FADE_FACTOR) >> 8;
  294. g = (g * FADE_FACTOR) >> 8;
  295. b = (b * FADE_FACTOR) >> 8;
  296. frameBuf[y][x][0] = r;
  297. frameBuf[y][x][1] = g;
  298. frameBuf[y][x][2] = b;
  299. matrix->drawPixel(x, y, matrix->color565(r, g, b));
  300. }
  301. }
  302.  
  303. // If in explosion mode
  304. if (inExplosion) {
  305. // draw explosion
  306. drawExplosion(now, collisionX, collisionY);
  307.  
  308. // check if explosion ended
  309. if (now - explosionStartTime > EXPLOSION_DURATION) {
  310. inExplosion = false;
  311. // reset scene
  312. resetScene();
  313. }
  314.  
  315. // done with this frame
  316. matrix->flipDMABuffer();
  317. yield();
  318. return;
  319. }
  320.  
  321. // 2) Normal swirl dance
  322. // Warp tilt
  323. float warpPhase = 2.0f * M_PI * (float)((now % WARP_PERIOD_MS) / (double)WARP_PERIOD_MS);
  324. float tiltAngle = WARP_MAX_ANGLE * sinf(warpPhase);
  325.  
  326. // Color cycle
  327. uint8_t timeHueOffset = (now % COLOR_CYCLE_MS) * 256 / COLOR_CYCLE_MS;
  328.  
  329. // swirl orbit update
  330. swirlOrbitAngle += swirlOrbitSpeed;
  331. if (swirlOrbitAngle > 2*M_PI) swirlOrbitAngle -= 2*M_PI;
  332. float cosO = cosf(swirlOrbitAngle);
  333. float sinO = sinf(swirlOrbitAngle);
  334. swirlACenterX = swirlACenterX_init + swirlOrbitRadius * cosO;
  335. swirlACenterY = swirlACenterY_init + swirlOrbitRadius * sinO;
  336. swirlBCenterX = swirlBCenterX_init - swirlOrbitRadius * cosO;
  337. swirlBCenterY = swirlBCenterY_init - swirlOrbitRadius * sinO;
  338.  
  339. // update swirl rotations
  340. rotAx += speedAx; if (rotAx>2*M_PI) rotAx-=2*M_PI;
  341. rotAy += speedAy; if (rotAy>2*M_PI) rotAy-=2*M_PI;
  342. rotAz += speedAz; if (rotAz>2*M_PI) rotAz-=2*M_PI;
  343. rotBx += speedBx; if (rotBx>2*M_PI) rotBx-=2*M_PI;
  344. rotBy += speedBy; if (rotBy>2*M_PI) rotBy-=2*M_PI;
  345. rotBz += speedBz; if (rotBz>2*M_PI) rotBz-=2*M_PI;
  346.  
  347. // draw swirl A
  348. drawSwirl(swirlA, swirlACenterX, swirlACenterY, rotAx, rotAy, rotAz, tiltAngle, timeHueOffset);
  349. // draw swirl B
  350. drawSwirl(swirlB, swirlBCenterX, swirlBCenterY, rotBx, rotBy, rotBz, tiltAngle, timeHueOffset);
  351.  
  352. // 3) Check collision
  353. float dx = swirlACenterX - swirlBCenterX;
  354. float dy = swirlACenterY - swirlBCenterY;
  355. float distSq = dx*dx + dy*dy;
  356. // if they are very close => collision
  357. if (distSq < 8.0f*8.0f) {
  358. inExplosion = true;
  359. explosionStartTime = now;
  360. // store collision coords in swirl local space for the explosion center
  361. collisionX = (swirlACenterX + swirlBCenterX)*0.5f;
  362. collisionY = (swirlACenterY + swirlBCenterY)*0.5f;
  363. }
  364.  
  365. matrix->flipDMABuffer();
  366. yield();
  367. }
  368.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement