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.
 
 
 
 
 
 

806 lines
22 KiB

  1. /*
  2. * cacademo various demo effects for libcaca
  3. * Copyright (c) 1998 Michele Bini <mibin@tin.it>
  4. * 2003-2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * 2004-2006 Sam Hocevar <sam@zoy.org>
  6. * All Rights Reserved
  7. *
  8. * $Id$
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the Do What The Fuck You Want To
  12. * Public License, Version 2, as published by Sam Hocevar. See
  13. * http://sam.zoy.org/wtfpl/COPYING for more details.
  14. */
  15. #include "config.h"
  16. #include "common.h"
  17. #if !defined(__KERNEL__)
  18. # include <stdio.h>
  19. # include <stdlib.h>
  20. # include <string.h>
  21. # include <math.h>
  22. # ifndef M_PI
  23. # define M_PI 3.14159265358979323846
  24. # endif
  25. #endif
  26. #include "cucul.h"
  27. #include "caca.h"
  28. enum action { PREPARE, INIT, UPDATE, RENDER, FREE };
  29. void transition(cucul_canvas_t *, int, int);
  30. void plasma(enum action, cucul_canvas_t *);
  31. void metaballs(enum action, cucul_canvas_t *);
  32. void moire(enum action, cucul_canvas_t *);
  33. void langton(enum action, cucul_canvas_t *);
  34. void matrix(enum action, cucul_canvas_t *);
  35. void (*fn[])(enum action, cucul_canvas_t *) =
  36. {
  37. plasma,
  38. metaballs,
  39. moire,
  40. //langton,
  41. matrix,
  42. };
  43. #define DEMOS (sizeof(fn)/sizeof(*fn))
  44. #define DEMO_FRAMES cucul_rand(500, 1000)
  45. #define TRANSITION_FRAMES 40
  46. #define TRANSITION_COUNT 2
  47. #define TRANSITION_CIRCLE 0
  48. #define TRANSITION_STAR 1
  49. /* Common macros for dither-based demos */
  50. #define XSIZ 256
  51. #define YSIZ 256
  52. /* Global variables */
  53. static int frame = 0;
  54. int main(int argc, char **argv)
  55. {
  56. static caca_display_t *dp;
  57. static cucul_canvas_t *frontcv, *backcv, *mask;
  58. int demo, next = -1, pause = 0, next_transition = DEMO_FRAMES;
  59. unsigned int i;
  60. int tmode = cucul_rand(0, TRANSITION_COUNT);
  61. /* Set up two canvases, a mask, and attach a display to the front one */
  62. frontcv = cucul_create_canvas(0, 0);
  63. backcv = cucul_create_canvas(0, 0);
  64. mask = cucul_create_canvas(0, 0);
  65. dp = caca_create_display(frontcv);
  66. if(!dp)
  67. return 1;
  68. cucul_set_canvas_size(backcv, cucul_get_canvas_width(frontcv),
  69. cucul_get_canvas_height(frontcv));
  70. cucul_set_canvas_size(mask, cucul_get_canvas_width(frontcv),
  71. cucul_get_canvas_height(frontcv));
  72. caca_set_display_time(dp, 20000);
  73. /* Initialise all demos' lookup tables */
  74. for(i = 0; i < DEMOS; i++)
  75. fn[i](PREPARE, frontcv);
  76. /* Choose a demo at random */
  77. demo = cucul_rand(0, DEMOS);
  78. fn[demo](INIT, frontcv);
  79. for(;;)
  80. {
  81. /* Handle events */
  82. caca_event_t ev;
  83. while(caca_get_event(dp, CACA_EVENT_KEY_PRESS
  84. | CACA_EVENT_QUIT, &ev, 0))
  85. {
  86. if(ev.type == CACA_EVENT_QUIT)
  87. goto end;
  88. switch(ev.data.key.ch)
  89. {
  90. case CACA_KEY_ESCAPE:
  91. case CACA_KEY_CTRL_C:
  92. case CACA_KEY_CTRL_Z:
  93. goto end;
  94. case ' ':
  95. pause = !pause;
  96. break;
  97. case '\r':
  98. if(next == -1)
  99. next_transition = frame;
  100. break;
  101. }
  102. }
  103. /* Resize the spare canvas, just in case the main one changed */
  104. cucul_set_canvas_size(backcv, cucul_get_canvas_width(frontcv),
  105. cucul_get_canvas_height(frontcv));
  106. cucul_set_canvas_size(mask, cucul_get_canvas_width(frontcv),
  107. cucul_get_canvas_height(frontcv));
  108. if(pause)
  109. goto paused;
  110. /* Update demo's data */
  111. fn[demo](UPDATE, frontcv);
  112. /* Handle transitions */
  113. if(frame == next_transition)
  114. {
  115. next = cucul_rand(0, DEMOS);
  116. if(next == demo)
  117. next = (next + 1) % DEMOS;
  118. fn[next](INIT, backcv);
  119. }
  120. else if(frame == next_transition + TRANSITION_FRAMES)
  121. {
  122. fn[demo](FREE, frontcv);
  123. demo = next;
  124. next = -1;
  125. next_transition = frame + DEMO_FRAMES;
  126. tmode = cucul_rand(0, TRANSITION_COUNT);
  127. }
  128. if(next != -1)
  129. fn[next](UPDATE, backcv);
  130. frame++;
  131. paused:
  132. /* Render main demo's canvas */
  133. fn[demo](RENDER, frontcv);
  134. /* If a transition is on its way, render it */
  135. if(next != -1)
  136. {
  137. fn[next](RENDER, backcv);
  138. cucul_set_color_ansi(mask, CUCUL_LIGHTGRAY, CUCUL_BLACK);
  139. cucul_clear_canvas(mask);
  140. cucul_set_color_ansi(mask, CUCUL_WHITE, CUCUL_WHITE);
  141. transition(mask, tmode,
  142. 100 * (frame - next_transition) / TRANSITION_FRAMES);
  143. cucul_blit(frontcv, 0, 0, backcv, mask);
  144. }
  145. cucul_set_color_ansi(frontcv, CUCUL_WHITE, CUCUL_BLUE);
  146. if(frame < 100)
  147. cucul_put_str(frontcv, cucul_get_canvas_width(frontcv) - 30,
  148. cucul_get_canvas_height(frontcv) - 2,
  149. " -=[ Powered by libcaca ]=- ");
  150. caca_refresh_display(dp);
  151. }
  152. end:
  153. if(next != -1)
  154. fn[next](FREE, frontcv);
  155. fn[demo](FREE, frontcv);
  156. caca_free_display(dp);
  157. cucul_free_canvas(mask);
  158. cucul_free_canvas(backcv);
  159. cucul_free_canvas(frontcv);
  160. return 0;
  161. }
  162. /* Transitions */
  163. void transition(cucul_canvas_t *mask, int tmode, int completed)
  164. {
  165. static float const star[] =
  166. {
  167. 0.000000, -1.000000,
  168. 0.308000, -0.349000,
  169. 0.992000, -0.244000,
  170. 0.500000, 0.266000,
  171. 0.632000, 0.998000,
  172. 0.008000, 0.659000,
  173. -0.601000, 0.995000,
  174. -0.496000, 0.275000,
  175. -0.997000, -0.244000,
  176. -0.313000, -0.349000
  177. };
  178. static float star_rot[sizeof(star)/sizeof(*star)];
  179. float mulx = 0.0075f * completed * cucul_get_canvas_width(mask);
  180. float muly = 0.0075f * completed * cucul_get_canvas_height(mask);
  181. int w2 = cucul_get_canvas_width(mask) / 2;
  182. int h2 = cucul_get_canvas_height(mask) / 2;
  183. float angle = (0.0075f * completed * 360) * 3.14 / 180, x, y;
  184. unsigned int i;
  185. switch(tmode)
  186. {
  187. case TRANSITION_STAR:
  188. /* Compute rotated coordinates */
  189. for(i = 0; i < (sizeof(star) / sizeof(*star)) / 2; i++)
  190. {
  191. x = star[i * 2];
  192. y = star[i * 2 + 1];
  193. star_rot[i * 2] = x * cos(angle) - y * sin(angle);
  194. star_rot[i * 2 + 1] = y * cos(angle) + x * sin(angle);
  195. }
  196. mulx *= 1.8;
  197. muly *= 1.8;
  198. #define DO_TRI(a, b, c) \
  199. cucul_fill_triangle(mask, \
  200. star_rot[(a)*2] * mulx + w2, star_rot[(a)*2+1] * muly + h2, \
  201. star_rot[(b)*2] * mulx + w2, star_rot[(b)*2+1] * muly + h2, \
  202. star_rot[(c)*2] * mulx + w2, star_rot[(c)*2+1] * muly + h2, '#')
  203. DO_TRI(0, 1, 9);
  204. DO_TRI(1, 2, 3);
  205. DO_TRI(3, 4, 5);
  206. DO_TRI(5, 6, 7);
  207. DO_TRI(7, 8, 9);
  208. DO_TRI(9, 1, 5);
  209. DO_TRI(9, 5, 7);
  210. DO_TRI(1, 3, 5);
  211. break;
  212. case TRANSITION_CIRCLE:
  213. cucul_fill_ellipse(mask, w2, h2, mulx, muly, '#');
  214. break;
  215. }
  216. }
  217. /* The plasma effect */
  218. #define TABLEX (XSIZ * 2)
  219. #define TABLEY (YSIZ * 2)
  220. static uint8_t table[TABLEX * TABLEY];
  221. static void do_plasma(uint8_t *,
  222. double, double, double, double, double, double);
  223. void plasma(enum action action, cucul_canvas_t *cv)
  224. {
  225. static cucul_dither_t *dither;
  226. static uint8_t *screen;
  227. static unsigned int red[256], green[256], blue[256], alpha[256];
  228. static double r[3], R[6];
  229. int i, x, y;
  230. switch(action)
  231. {
  232. case PREPARE:
  233. /* Fill various tables */
  234. for(i = 0 ; i < 256; i++)
  235. red[i] = green[i] = blue[i] = alpha[i] = 0;
  236. for(i = 0; i < 3; i++)
  237. r[i] = (double)(cucul_rand(1, 1000)) / 60000 * M_PI;
  238. for(i = 0; i < 6; i++)
  239. R[i] = (double)(cucul_rand(1, 1000)) / 10000;
  240. for(y = 0 ; y < TABLEY ; y++)
  241. for(x = 0 ; x < TABLEX ; x++)
  242. {
  243. double tmp = (((double)((x - (TABLEX / 2)) * (x - (TABLEX / 2))
  244. + (y - (TABLEX / 2)) * (y - (TABLEX / 2))))
  245. * (M_PI / (TABLEX * TABLEX + TABLEY * TABLEY)));
  246. table[x + y * TABLEX] = (1.0 + sin(12.0 * sqrt(tmp))) * 256 / 6;
  247. }
  248. break;
  249. case INIT:
  250. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  251. dither = cucul_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
  252. break;
  253. case UPDATE:
  254. for(i = 0 ; i < 256; i++)
  255. {
  256. double z = ((double)i) / 256 * 6 * M_PI;
  257. red[i] = (1.0 + sin(z + r[1] * frame)) / 2 * 0xfff;
  258. blue[i] = (1.0 + cos(z + r[0] * (frame + 100))) / 2 * 0xfff;
  259. green[i] = (1.0 + cos(z + r[2] * (frame + 200))) / 2 * 0xfff;
  260. }
  261. /* Set the palette */
  262. cucul_set_dither_palette(dither, red, green, blue, alpha);
  263. do_plasma(screen,
  264. (1.0 + sin(((double)frame) * R[0])) / 2,
  265. (1.0 + sin(((double)frame) * R[1])) / 2,
  266. (1.0 + sin(((double)frame) * R[2])) / 2,
  267. (1.0 + sin(((double)frame) * R[3])) / 2,
  268. (1.0 + sin(((double)frame) * R[4])) / 2,
  269. (1.0 + sin(((double)frame) * R[5])) / 2);
  270. break;
  271. case RENDER:
  272. cucul_dither_bitmap(cv, 0, 0,
  273. cucul_get_canvas_width(cv),
  274. cucul_get_canvas_height(cv),
  275. dither, screen);
  276. break;
  277. case FREE:
  278. free(screen);
  279. cucul_free_dither(dither);
  280. break;
  281. }
  282. }
  283. static void do_plasma(uint8_t *pixels, double x_1, double y_1,
  284. double x_2, double y_2, double x_3, double y_3)
  285. {
  286. unsigned int X1 = x_1 * (TABLEX / 2),
  287. Y1 = y_1 * (TABLEY / 2),
  288. X2 = x_2 * (TABLEX / 2),
  289. Y2 = y_2 * (TABLEY / 2),
  290. X3 = x_3 * (TABLEX / 2),
  291. Y3 = y_3 * (TABLEY / 2);
  292. unsigned int y;
  293. uint8_t * t1 = table + X1 + Y1 * TABLEX,
  294. * t2 = table + X2 + Y2 * TABLEX,
  295. * t3 = table + X3 + Y3 * TABLEX;
  296. for(y = 0; y < YSIZ; y++)
  297. {
  298. unsigned int x;
  299. uint8_t * tmp = pixels + y * YSIZ;
  300. unsigned int ty = y * TABLEX, tmax = ty + XSIZ;
  301. for(x = 0; ty < tmax; ty++, tmp++)
  302. tmp[0] = t1[ty] + t2[ty] + t3[ty];
  303. }
  304. }
  305. /* The metaball effect */
  306. #define METASIZE (XSIZ/2)
  307. #define METABALLS 12
  308. #define CROPBALL 200 /* Colour index where to crop balls */
  309. static uint8_t metaball[METASIZE * METASIZE];
  310. static void create_ball(void);
  311. static void draw_ball(uint8_t *, unsigned int, unsigned int);
  312. void metaballs(enum action action, cucul_canvas_t *cv)
  313. {
  314. static cucul_dither_t *cucul_dither;
  315. static uint8_t *screen;
  316. static unsigned int r[256], g[256], b[256], a[256];
  317. static float dd[METABALLS], di[METABALLS], dj[METABALLS], dk[METABALLS];
  318. static unsigned int x[METABALLS], y[METABALLS];
  319. static float i = 10.0, j = 17.0, k = 11.0;
  320. static double offset[360 + 80];
  321. static unsigned int angleoff;
  322. int n, angle;
  323. switch(action)
  324. {
  325. case PREPARE:
  326. /* Make the palette eatable by libcaca */
  327. for(n = 0; n < 256; n++)
  328. r[n] = g[n] = b[n] = a[n] = 0x0;
  329. r[255] = g[255] = b[255] = 0xfff;
  330. /* Generate ball sprite */
  331. create_ball();
  332. for(n = 0; n < METABALLS; n++)
  333. {
  334. dd[n] = cucul_rand(0, 100);
  335. di[n] = (float)cucul_rand(500, 4000) / 6000.0;
  336. dj[n] = (float)cucul_rand(500, 4000) / 6000.0;
  337. dk[n] = (float)cucul_rand(500, 4000) / 6000.0;
  338. }
  339. angleoff = cucul_rand(0, 360);
  340. for(n = 0; n < 360 + 80; n++)
  341. offset[n] = 1.0 + sin((double)(n * M_PI / 60));
  342. break;
  343. case INIT:
  344. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  345. /* Create a libcucul dither smaller than our pixel buffer, so that we
  346. * display only the interesting part of it */
  347. cucul_dither = cucul_create_dither(8, XSIZ - METASIZE, YSIZ - METASIZE,
  348. XSIZ, 0, 0, 0, 0);
  349. break;
  350. case UPDATE:
  351. angle = (frame + angleoff) % 360;
  352. /* Crop the palette */
  353. for(n = CROPBALL; n < 255; n++)
  354. {
  355. int t1, t2, t3;
  356. double c1 = offset[angle];
  357. double c2 = offset[angle + 40];
  358. double c3 = offset[angle + 80];
  359. t1 = n < 0x40 ? 0 : n < 0xc0 ? (n - 0x40) * 0x20 : 0xfff;
  360. t2 = n < 0xe0 ? 0 : (n - 0xe0) * 0x80;
  361. t3 = n < 0x40 ? n * 0x40 : 0xfff;
  362. r[n] = (c1 * t1 + c2 * t2 + c3 * t3) / 4;
  363. g[n] = (c1 * t2 + c2 * t3 + c3 * t1) / 4;
  364. b[n] = (c1 * t3 + c2 * t1 + c3 * t2) / 4;
  365. }
  366. /* Set the palette */
  367. cucul_set_dither_palette(cucul_dither, r, g, b, a);
  368. /* Silly paths for our balls */
  369. for(n = 0; n < METABALLS; n++)
  370. {
  371. float u = di[n] * i + dj[n] * j + dk[n] * sin(di[n] * k);
  372. float v = dd[n] + di[n] * j + dj[n] * k + dk[n] * sin(dk[n] * i);
  373. u = sin(i + u * 2.1) * (1.0 + sin(u));
  374. v = sin(j + v * 1.9) * (1.0 + sin(v));
  375. x[n] = (XSIZ - METASIZE) / 2 + u * (XSIZ - METASIZE) / 4;
  376. y[n] = (YSIZ - METASIZE) / 2 + v * (YSIZ - METASIZE) / 4;
  377. }
  378. i += 0.011;
  379. j += 0.017;
  380. k += 0.019;
  381. memset(screen, 0, XSIZ * YSIZ);
  382. for(n = 0; n < METABALLS; n++)
  383. draw_ball(screen, x[n], y[n]);
  384. break;
  385. case RENDER:
  386. cucul_dither_bitmap(cv, 0, 0,
  387. cucul_get_canvas_width(cv),
  388. cucul_get_canvas_height(cv),
  389. cucul_dither, screen + (METASIZE / 2) * (1 + XSIZ));
  390. break;
  391. case FREE:
  392. free(screen);
  393. cucul_free_dither(cucul_dither);
  394. break;
  395. }
  396. }
  397. static void create_ball(void)
  398. {
  399. int x, y;
  400. float distance;
  401. for(y = 0; y < METASIZE; y++)
  402. for(x = 0; x < METASIZE; x++)
  403. {
  404. distance = ((METASIZE/2) - x) * ((METASIZE/2) - x)
  405. + ((METASIZE/2) - y) * ((METASIZE/2) - y);
  406. distance = sqrt(distance) * 64 / METASIZE;
  407. metaball[x + y * METASIZE] = distance > 15 ? 0 : (255 - distance) * 15;
  408. }
  409. }
  410. static void draw_ball(uint8_t *screen, unsigned int bx, unsigned int by)
  411. {
  412. unsigned int color;
  413. unsigned int i, e = 0;
  414. unsigned int b = (by * XSIZ) + bx;
  415. for(i = 0; i < METASIZE * METASIZE; i++)
  416. {
  417. color = screen[b] + metaball[i];
  418. if(color > 255)
  419. color = 255;
  420. screen[b] = color;
  421. if(e == METASIZE)
  422. {
  423. e = 0;
  424. b += XSIZ - METASIZE;
  425. }
  426. b++;
  427. e++;
  428. }
  429. }
  430. /* The moiré effect */
  431. #define DISCSIZ (XSIZ*2)
  432. #define DISCTHICKNESS (XSIZ*15/40)
  433. static uint8_t disc[DISCSIZ * DISCSIZ];
  434. static void put_disc(uint8_t *, int, int);
  435. static void draw_line(int, int, char);
  436. void moire(enum action action, cucul_canvas_t *cv)
  437. {
  438. static cucul_dither_t *dither;
  439. static uint8_t *screen;
  440. static float d[6];
  441. static unsigned int red[256], green[256], blue[256], alpha[256];
  442. int i, x, y;
  443. switch(action)
  444. {
  445. case PREPARE:
  446. /* Fill various tables */
  447. for(i = 0 ; i < 256; i++)
  448. red[i] = green[i] = blue[i] = alpha[i] = 0;
  449. for(i = 0; i < 6; i++)
  450. d[i] = ((float)cucul_rand(50, 70)) / 1000.0;
  451. red[0] = green[0] = blue[0] = 0x777;
  452. red[1] = green[1] = blue[1] = 0xfff;
  453. /* Fill the circle */
  454. for(i = DISCSIZ * 2; i > 0; i -= DISCTHICKNESS)
  455. {
  456. int t, dx, dy;
  457. for(t = 0, dx = 0, dy = i; dx <= dy; dx++)
  458. {
  459. draw_line(dx / 3, dy / 3, (i / DISCTHICKNESS) % 2);
  460. draw_line(dy / 3, dx / 3, (i / DISCTHICKNESS) % 2);
  461. t += t > 0 ? dx - dy-- : dx;
  462. }
  463. }
  464. break;
  465. case INIT:
  466. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  467. dither = cucul_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
  468. break;
  469. case UPDATE:
  470. memset(screen, 0, XSIZ * YSIZ);
  471. /* Set the palette */
  472. red[0] = 0.5 * (1 + sin(d[0] * (frame + 1000))) * 0xfff;
  473. green[0] = 0.5 * (1 + cos(d[1] * frame)) * 0xfff;
  474. blue[0] = 0.5 * (1 + cos(d[2] * (frame + 3000))) * 0xfff;
  475. red[1] = 0.5 * (1 + sin(d[3] * (frame + 2000))) * 0xfff;
  476. green[1] = 0.5 * (1 + cos(d[4] * frame + 5.0)) * 0xfff;
  477. blue[1] = 0.5 * (1 + cos(d[5] * (frame + 4000))) * 0xfff;
  478. cucul_set_dither_palette(dither, red, green, blue, alpha);
  479. /* Draw circles */
  480. x = cos(d[0] * (frame + 1000)) * 128.0 + (XSIZ / 2);
  481. y = sin(0.11 * frame) * 128.0 + (YSIZ / 2);
  482. put_disc(screen, x, y);
  483. x = cos(0.13 * frame + 2.0) * 64.0 + (XSIZ / 2);
  484. y = sin(d[1] * (frame + 2000)) * 64.0 + (YSIZ / 2);
  485. put_disc(screen, x, y);
  486. break;
  487. case RENDER:
  488. cucul_dither_bitmap(cv, 0, 0,
  489. cucul_get_canvas_width(cv),
  490. cucul_get_canvas_height(cv),
  491. dither, screen);
  492. break;
  493. case FREE:
  494. free(screen);
  495. cucul_free_dither(dither);
  496. break;
  497. }
  498. }
  499. static void put_disc(uint8_t *screen, int x, int y)
  500. {
  501. char *src = ((char*)disc) + (DISCSIZ / 2 - x) + (DISCSIZ / 2 - y) * DISCSIZ;
  502. int i, j;
  503. for(j = 0; j < YSIZ; j++)
  504. for(i = 0; i < XSIZ; i++)
  505. {
  506. screen[i + XSIZ * j] ^= src[i + DISCSIZ * j];
  507. }
  508. }
  509. static void draw_line(int x, int y, char color)
  510. {
  511. if(x == 0 || y == 0 || y > DISCSIZ / 2)
  512. return;
  513. if(x > DISCSIZ / 2)
  514. x = DISCSIZ / 2;
  515. memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) - y),
  516. color, 2 * x - 1);
  517. memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) + y - 1),
  518. color, 2 * x - 1);
  519. }
  520. /* Langton ant effect */
  521. #define ANTS 15
  522. #define ITER 2
  523. void langton(enum action action, cucul_canvas_t *cv)
  524. {
  525. static char gradient[] =
  526. {
  527. ' ', ' ', '.', '.', ':', ':', 'x', 'x',
  528. 'X', 'X', '&', '&', 'W', 'W', '@', '@',
  529. };
  530. static int steps[][2] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
  531. static uint8_t *screen;
  532. static int width, height;
  533. static int ax[ANTS], ay[ANTS], dir[ANTS];
  534. int i, a, x, y;
  535. switch(action)
  536. {
  537. case PREPARE:
  538. width = cucul_get_canvas_width(cv);
  539. height = cucul_get_canvas_height(cv);
  540. for(i = 0; i < ANTS; i++)
  541. {
  542. ax[i] = cucul_rand(0, width);
  543. ay[i] = cucul_rand(0, height);
  544. dir[i] = cucul_rand(0, 4);
  545. }
  546. break;
  547. case INIT:
  548. screen = malloc(width * height);
  549. memset(screen, 0, width * height);
  550. break;
  551. case UPDATE:
  552. for(i = 0; i < ITER; i++)
  553. {
  554. for(x = 0; x < width * height; x++)
  555. {
  556. uint8_t p = screen[x];
  557. if((p & 0x0f) > 1)
  558. screen[x] = p - 1;
  559. }
  560. for(a = 0; a < ANTS; a++)
  561. {
  562. uint8_t p = screen[ax[a] + width * ay[a]];
  563. if(p & 0x0f)
  564. {
  565. dir[a] = (dir[a] + 1) % 4;
  566. screen[ax[a] + width * ay[a]] = a << 4;
  567. }
  568. else
  569. {
  570. dir[a] = (dir[a] + 3) % 4;
  571. screen[ax[a] + width * ay[a]] = (a << 4) | 0x0f;
  572. }
  573. ax[a] = (width + ax[a] + steps[dir[a]][0]) % width;
  574. ay[a] = (height + ay[a] + steps[dir[a]][1]) % height;
  575. }
  576. }
  577. break;
  578. case RENDER:
  579. for(y = 0; y < height; y++)
  580. {
  581. for(x = 0; x < width; x++)
  582. {
  583. uint8_t p = screen[x + width * y];
  584. if(p & 0x0f)
  585. cucul_set_color_ansi(cv, CUCUL_WHITE, p >> 4);
  586. else
  587. cucul_set_color_ansi(cv, CUCUL_BLACK, CUCUL_BLACK);
  588. cucul_put_char(cv, x, y, gradient[p & 0x0f]);
  589. }
  590. }
  591. break;
  592. case FREE:
  593. free(screen);
  594. break;
  595. }
  596. }
  597. /* Matrix effect */
  598. #define MAXDROPS 500
  599. #define MINLEN 15
  600. #define MAXLEN 30
  601. void matrix(enum action action, cucul_canvas_t *cv)
  602. {
  603. static struct drop
  604. {
  605. int x, y, speed, len;
  606. char str[MAXLEN];
  607. }
  608. drop[MAXDROPS];
  609. int w, h, i, j;
  610. switch(action)
  611. {
  612. case PREPARE:
  613. for(i = 0; i < MAXDROPS; i++)
  614. {
  615. drop[i].x = cucul_rand(0, 1000);
  616. drop[i].y = cucul_rand(0, 1000);
  617. drop[i].speed = 5 + cucul_rand(0, 30);
  618. drop[i].len = MINLEN + cucul_rand(0, (MAXLEN - MINLEN));
  619. for(j = 0; j < MAXLEN; j++)
  620. drop[i].str[j] = cucul_rand('0', 'z');
  621. }
  622. break;
  623. case INIT:
  624. break;
  625. case UPDATE:
  626. w = cucul_get_canvas_width(cv);
  627. h = cucul_get_canvas_height(cv);
  628. for(i = 0; i < MAXDROPS && i < (w * h / 32); i++)
  629. {
  630. drop[i].y += drop[i].speed;
  631. if(drop[i].y > 1000)
  632. {
  633. drop[i].y -= 1000;
  634. drop[i].x = cucul_rand(0, 1000);
  635. }
  636. }
  637. break;
  638. case RENDER:
  639. w = cucul_get_canvas_width(cv);
  640. h = cucul_get_canvas_height(cv);
  641. cucul_set_color_ansi(cv, CUCUL_BLACK, CUCUL_BLACK);
  642. cucul_clear_canvas(cv);
  643. for(i = 0; i < MAXDROPS && i < (w * h / 32); i++)
  644. {
  645. int x, y;
  646. x = drop[i].x * w / 1000 / 2 * 2;
  647. y = drop[i].y * (h + MAXLEN) / 1000;
  648. for(j = 0; j < drop[i].len; j++)
  649. {
  650. unsigned int fg;
  651. if(j < 2)
  652. fg = CUCUL_WHITE;
  653. else if(j < drop[i].len / 4)
  654. fg = CUCUL_LIGHTGREEN;
  655. else if(j < drop[i].len * 4 / 5)
  656. fg = CUCUL_GREEN;
  657. else
  658. fg = CUCUL_DARKGRAY;
  659. cucul_set_color_ansi(cv, fg, CUCUL_BLACK);
  660. cucul_put_char(cv, x, y - j,
  661. drop[i].str[(y - j) % drop[i].len]);
  662. }
  663. }
  664. break;
  665. case FREE:
  666. break;
  667. }
  668. }