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.

преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 17 години
преди 17 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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-2012 Sam Hocevar <sam@hocevar.net>
  6. * All Rights Reserved
  7. *
  8. * This program is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What the Fuck You Want
  11. * to Public License, Version 2, as published by Sam Hocevar. See
  12. * http://www.wtfpl.net/ for more details.
  13. */
  14. #include "config.h"
  15. #if !defined(__KERNEL__)
  16. # include <stdio.h>
  17. # include <stdlib.h>
  18. # include <string.h>
  19. # include <math.h>
  20. # ifndef M_PI
  21. # define M_PI 3.14159265358979323846
  22. # endif
  23. #endif
  24. #include "caca.h"
  25. enum action { PREPARE, INIT, UPDATE, RENDER, FREE };
  26. void transition(caca_canvas_t *, int, int);
  27. void plasma(enum action, caca_canvas_t *);
  28. void metaballs(enum action, caca_canvas_t *);
  29. void moire(enum action, caca_canvas_t *);
  30. void langton(enum action, caca_canvas_t *);
  31. void matrix(enum action, caca_canvas_t *);
  32. void rotozoom(enum action, caca_canvas_t *);
  33. void (*fn[])(enum action, caca_canvas_t *) =
  34. {
  35. plasma,
  36. metaballs,
  37. moire,
  38. /*langton,*/
  39. matrix,
  40. rotozoom,
  41. };
  42. #define DEMOS (sizeof(fn)/sizeof(*fn))
  43. #define DEMO_FRAMES caca_rand(500, 1000)
  44. #define TRANSITION_FRAMES 40
  45. #define TRANSITION_COUNT 5
  46. #define TRANSITION_CIRCLE 0
  47. #define TRANSITION_STAR 1
  48. #define TRANSITION_SQUARE 2
  49. #define TRANSITION_VLINES 3
  50. #define TRANSITION_HLINES 4
  51. /* Common macros for dither-based demos */
  52. #define XSIZ 256
  53. #define YSIZ 256
  54. /* Global variables */
  55. static int frame = 0;
  56. int main(int argc, char **argv)
  57. {
  58. static caca_display_t *dp;
  59. static caca_canvas_t *frontcv, *backcv, *mask;
  60. int demo, next = -1, paused = 0, next_transition = DEMO_FRAMES;
  61. unsigned int i;
  62. int tmode = caca_rand(0, TRANSITION_COUNT);
  63. /* Set up two canvases, a mask, and attach a display to the front one */
  64. frontcv = caca_create_canvas(0, 0);
  65. backcv = caca_create_canvas(0, 0);
  66. mask = caca_create_canvas(0, 0);
  67. dp = caca_create_display(frontcv);
  68. if(!dp)
  69. return 1;
  70. caca_set_canvas_size(backcv, caca_get_canvas_width(frontcv),
  71. caca_get_canvas_height(frontcv));
  72. caca_set_canvas_size(mask, caca_get_canvas_width(frontcv),
  73. caca_get_canvas_height(frontcv));
  74. caca_set_display_time(dp, 20000);
  75. /* Initialise all demos' lookup tables */
  76. for(i = 0; i < DEMOS; i++)
  77. fn[i](PREPARE, frontcv);
  78. /* Choose a demo at random */
  79. demo = caca_rand(0, DEMOS);
  80. fn[demo](INIT, frontcv);
  81. for(;;)
  82. {
  83. /* Handle events */
  84. caca_event_t ev;
  85. while(caca_get_event(dp, CACA_EVENT_KEY_PRESS
  86. | CACA_EVENT_QUIT, &ev, 0))
  87. {
  88. if(caca_get_event_type(&ev) == CACA_EVENT_QUIT)
  89. goto end;
  90. switch(caca_get_event_key_ch(&ev))
  91. {
  92. case CACA_KEY_ESCAPE:
  93. case CACA_KEY_CTRL_C:
  94. case CACA_KEY_CTRL_Z:
  95. goto end;
  96. case ' ':
  97. paused = !paused;
  98. break;
  99. case '\r':
  100. if(next == -1)
  101. next_transition = frame;
  102. break;
  103. }
  104. }
  105. /* Resize the spare canvas, just in case the main one changed */
  106. caca_set_canvas_size(backcv, caca_get_canvas_width(frontcv),
  107. caca_get_canvas_height(frontcv));
  108. caca_set_canvas_size(mask, caca_get_canvas_width(frontcv),
  109. caca_get_canvas_height(frontcv));
  110. if(paused)
  111. goto _paused;
  112. /* Update demo's data */
  113. fn[demo](UPDATE, frontcv);
  114. /* Handle transitions */
  115. if(frame == next_transition)
  116. {
  117. next = caca_rand(0, DEMOS);
  118. if(next == demo)
  119. next = (next + 1) % DEMOS;
  120. fn[next](INIT, backcv);
  121. }
  122. else if(frame == next_transition + TRANSITION_FRAMES)
  123. {
  124. fn[demo](FREE, frontcv);
  125. demo = next;
  126. next = -1;
  127. next_transition = frame + DEMO_FRAMES;
  128. tmode = caca_rand(0, TRANSITION_COUNT);
  129. }
  130. if(next != -1)
  131. fn[next](UPDATE, backcv);
  132. frame++;
  133. _paused:
  134. /* Render main demo's canvas */
  135. fn[demo](RENDER, frontcv);
  136. /* If a transition is on its way, render it */
  137. if(next != -1)
  138. {
  139. fn[next](RENDER, backcv);
  140. caca_set_color_ansi(mask, CACA_LIGHTGRAY, CACA_BLACK);
  141. caca_clear_canvas(mask);
  142. caca_set_color_ansi(mask, CACA_WHITE, CACA_WHITE);
  143. transition(mask, tmode,
  144. 100 * (frame - next_transition) / TRANSITION_FRAMES);
  145. caca_blit(frontcv, 0, 0, backcv, mask);
  146. }
  147. caca_set_color_ansi(frontcv, CACA_WHITE, CACA_BLUE);
  148. if(frame < 100)
  149. caca_put_str(frontcv, caca_get_canvas_width(frontcv) - 30,
  150. caca_get_canvas_height(frontcv) - 2,
  151. " -=[ Powered by libcaca ]=- ");
  152. caca_refresh_display(dp);
  153. }
  154. end:
  155. if(next != -1)
  156. fn[next](FREE, frontcv);
  157. fn[demo](FREE, frontcv);
  158. caca_free_display(dp);
  159. caca_free_canvas(mask);
  160. caca_free_canvas(backcv);
  161. caca_free_canvas(frontcv);
  162. return 0;
  163. }
  164. /* Transitions */
  165. void transition(caca_canvas_t *mask, int tmode, int completed)
  166. {
  167. static float const star[] =
  168. {
  169. 0.000000, -1.000000,
  170. 0.308000, -0.349000,
  171. 0.992000, -0.244000,
  172. 0.500000, 0.266000,
  173. 0.632000, 0.998000,
  174. 0.008000, 0.659000,
  175. -0.601000, 0.995000,
  176. -0.496000, 0.275000,
  177. -0.997000, -0.244000,
  178. -0.313000, -0.349000
  179. };
  180. static float star_rot[sizeof(star)/sizeof(*star)];
  181. static float const square[] =
  182. {
  183. -1, -1,
  184. 1, -1,
  185. 1, 1,
  186. -1, 1
  187. };
  188. static float square_rot[sizeof(square)/sizeof(*square)];
  189. float mulx = 0.0075f * completed * caca_get_canvas_width(mask);
  190. float muly = 0.0075f * completed * caca_get_canvas_height(mask);
  191. int w2 = caca_get_canvas_width(mask) / 2;
  192. int h2 = caca_get_canvas_height(mask) / 2;
  193. float angle = (0.0075f * completed * 360) * 3.14 / 180, x, y;
  194. unsigned int i;
  195. int w = caca_get_canvas_width(mask);
  196. int h = caca_get_canvas_height(mask);
  197. switch(tmode)
  198. {
  199. case TRANSITION_SQUARE:
  200. /* Compute rotated coordinates */
  201. for(i = 0; i < (sizeof(square) / sizeof(*square)) / 2; i++)
  202. {
  203. x = square[i * 2];
  204. y = square[i * 2 + 1];
  205. square_rot[i * 2] = x * cos(angle) - y * sin(angle);
  206. square_rot[i * 2 + 1] = y * cos(angle) + x * sin(angle);
  207. }
  208. mulx *= 1.8;
  209. muly *= 1.8;
  210. caca_fill_triangle(mask,
  211. square_rot[0*2] * mulx + w2, square_rot[0*2+1] * muly + h2, \
  212. square_rot[1*2] * mulx + w2, square_rot[1*2+1] * muly + h2, \
  213. square_rot[2*2] * mulx + w2, square_rot[2*2+1] * muly + h2, '#');
  214. caca_fill_triangle(mask,
  215. square_rot[0*2] * mulx + w2, square_rot[0*2+1] * muly + h2, \
  216. square_rot[2*2] * mulx + w2, square_rot[2*2+1] * muly + h2, \
  217. square_rot[3*2] * mulx + w2, square_rot[3*2+1] * muly + h2, '#');
  218. break;
  219. case TRANSITION_STAR:
  220. /* Compute rotated coordinates */
  221. for(i = 0; i < (sizeof(star) / sizeof(*star)) / 2; i++)
  222. {
  223. x = star[i * 2];
  224. y = star[i * 2 + 1];
  225. star_rot[i * 2] = x * cos(angle) - y * sin(angle);
  226. star_rot[i * 2 + 1] = y * cos(angle) + x * sin(angle);
  227. }
  228. mulx *= 1.8;
  229. muly *= 1.8;
  230. #define DO_TRI(a, b, c) \
  231. caca_fill_triangle(mask, \
  232. star_rot[(a)*2] * mulx + w2, star_rot[(a)*2+1] * muly + h2, \
  233. star_rot[(b)*2] * mulx + w2, star_rot[(b)*2+1] * muly + h2, \
  234. star_rot[(c)*2] * mulx + w2, star_rot[(c)*2+1] * muly + h2, '#')
  235. DO_TRI(0, 1, 9);
  236. DO_TRI(1, 2, 3);
  237. DO_TRI(3, 4, 5);
  238. DO_TRI(5, 6, 7);
  239. DO_TRI(7, 8, 9);
  240. DO_TRI(9, 1, 5);
  241. DO_TRI(9, 5, 7);
  242. DO_TRI(1, 3, 5);
  243. break;
  244. case TRANSITION_CIRCLE:
  245. caca_fill_ellipse(mask, w2, h2, mulx, muly, '#');
  246. break;
  247. case TRANSITION_VLINES:
  248. for(i = 0; i < 8; i++)
  249. {
  250. int z = ((i & 1) ? w : (-w)/2) * (100 - completed) / 100;
  251. caca_fill_box(mask, i * w / 8, z , (w / 8) + 1, z + h, '#');
  252. }
  253. break;
  254. case TRANSITION_HLINES:
  255. for(i = 0; i < 6; i++)
  256. {
  257. int z = ((i & 1) ? w : (-w)/2) * (100 - completed) / 100;
  258. caca_fill_box(mask, z, i * h / 6, z + w, (h / 6) + 1, '#');
  259. }
  260. break;
  261. }
  262. }
  263. /* The plasma effect */
  264. #define TABLEX (XSIZ * 2)
  265. #define TABLEY (YSIZ * 2)
  266. static uint8_t table[TABLEX * TABLEY];
  267. static void do_plasma(uint8_t *,
  268. double, double, double, double, double, double);
  269. void plasma(enum action action, caca_canvas_t *cv)
  270. {
  271. static caca_dither_t *dither;
  272. static uint8_t *screen;
  273. static uint32_t red[256], green[256], blue[256], alpha[256];
  274. static double r[3], R[6];
  275. int i, x, y;
  276. switch(action)
  277. {
  278. case PREPARE:
  279. /* Fill various tables */
  280. for(i = 0 ; i < 256; i++)
  281. red[i] = green[i] = blue[i] = alpha[i] = 0;
  282. for(i = 0; i < 3; i++)
  283. r[i] = (double)(caca_rand(1, 1000)) / 60000 * M_PI;
  284. for(i = 0; i < 6; i++)
  285. R[i] = (double)(caca_rand(1, 1000)) / 10000;
  286. for(y = 0 ; y < TABLEY ; y++)
  287. for(x = 0 ; x < TABLEX ; x++)
  288. {
  289. double tmp = (((double)((x - (TABLEX / 2)) * (x - (TABLEX / 2))
  290. + (y - (TABLEX / 2)) * (y - (TABLEX / 2))))
  291. * (M_PI / (TABLEX * TABLEX + TABLEY * TABLEY)));
  292. table[x + y * TABLEX] = (1.0 + sin(12.0 * sqrt(tmp))) * 256 / 6;
  293. }
  294. break;
  295. case INIT:
  296. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  297. dither = caca_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
  298. break;
  299. case UPDATE:
  300. for(i = 0 ; i < 256; i++)
  301. {
  302. double z = ((double)i) / 256 * 6 * M_PI;
  303. red[i] = (1.0 + sin(z + r[1] * frame)) / 2 * 0xfff;
  304. blue[i] = (1.0 + cos(z + r[0] * (frame + 100))) / 2 * 0xfff;
  305. green[i] = (1.0 + cos(z + r[2] * (frame + 200))) / 2 * 0xfff;
  306. }
  307. /* Set the palette */
  308. caca_set_dither_palette(dither, red, green, blue, alpha);
  309. do_plasma(screen,
  310. (1.0 + sin(((double)frame) * R[0])) / 2,
  311. (1.0 + sin(((double)frame) * R[1])) / 2,
  312. (1.0 + sin(((double)frame) * R[2])) / 2,
  313. (1.0 + sin(((double)frame) * R[3])) / 2,
  314. (1.0 + sin(((double)frame) * R[4])) / 2,
  315. (1.0 + sin(((double)frame) * R[5])) / 2);
  316. break;
  317. case RENDER:
  318. caca_dither_bitmap(cv, 0, 0,
  319. caca_get_canvas_width(cv),
  320. caca_get_canvas_height(cv),
  321. dither, screen);
  322. break;
  323. case FREE:
  324. free(screen);
  325. caca_free_dither(dither);
  326. break;
  327. }
  328. }
  329. static void do_plasma(uint8_t *pixels, double x_1, double y_1,
  330. double x_2, double y_2, double x_3, double y_3)
  331. {
  332. unsigned int X1 = x_1 * (TABLEX / 2),
  333. Y1 = y_1 * (TABLEY / 2),
  334. X2 = x_2 * (TABLEX / 2),
  335. Y2 = y_2 * (TABLEY / 2),
  336. X3 = x_3 * (TABLEX / 2),
  337. Y3 = y_3 * (TABLEY / 2);
  338. unsigned int y;
  339. uint8_t * t1 = table + X1 + Y1 * TABLEX,
  340. * t2 = table + X2 + Y2 * TABLEX,
  341. * t3 = table + X3 + Y3 * TABLEX;
  342. for(y = 0; y < YSIZ; y++)
  343. {
  344. unsigned int x;
  345. uint8_t * tmp = pixels + y * YSIZ;
  346. unsigned int ty = y * TABLEX, tmax = ty + XSIZ;
  347. for(x = 0; ty < tmax; ty++, tmp++)
  348. tmp[0] = t1[ty] + t2[ty] + t3[ty];
  349. }
  350. }
  351. /* The metaball effect */
  352. #define METASIZE (XSIZ/2)
  353. #define METABALLS 12
  354. #define CROPBALL 200 /* Colour index where to crop balls */
  355. static uint8_t metaball[METASIZE * METASIZE];
  356. static void create_ball(void);
  357. static void draw_ball(uint8_t *, unsigned int, unsigned int);
  358. void metaballs(enum action action, caca_canvas_t *cv)
  359. {
  360. static caca_dither_t *caca_dither;
  361. static uint8_t *screen;
  362. static uint32_t r[256], g[256], b[256], a[256];
  363. static float dd[METABALLS], di[METABALLS], dj[METABALLS], dk[METABALLS];
  364. static unsigned int x[METABALLS], y[METABALLS];
  365. static float i = 10.0, j = 17.0, k = 11.0;
  366. static double offset[360 + 80];
  367. static unsigned int angleoff;
  368. int n, angle;
  369. switch(action)
  370. {
  371. case PREPARE:
  372. /* Make the palette eatable by libcaca */
  373. for(n = 0; n < 256; n++)
  374. r[n] = g[n] = b[n] = a[n] = 0x0;
  375. r[255] = g[255] = b[255] = 0xfff;
  376. /* Generate ball sprite */
  377. create_ball();
  378. for(n = 0; n < METABALLS; n++)
  379. {
  380. dd[n] = caca_rand(0, 100);
  381. di[n] = (float)caca_rand(500, 4000) / 6000.0;
  382. dj[n] = (float)caca_rand(500, 4000) / 6000.0;
  383. dk[n] = (float)caca_rand(500, 4000) / 6000.0;
  384. }
  385. angleoff = caca_rand(0, 360);
  386. for(n = 0; n < 360 + 80; n++)
  387. offset[n] = 1.0 + sin((double)(n * M_PI / 60));
  388. break;
  389. case INIT:
  390. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  391. /* Create a libcaca dither smaller than our pixel buffer, so that we
  392. * display only the interesting part of it */
  393. caca_dither = caca_create_dither(8, XSIZ - METASIZE, YSIZ - METASIZE,
  394. XSIZ, 0, 0, 0, 0);
  395. break;
  396. case UPDATE:
  397. angle = (frame + angleoff) % 360;
  398. /* Crop the palette */
  399. for(n = CROPBALL; n < 255; n++)
  400. {
  401. int t1, t2, t3;
  402. double c1 = offset[angle];
  403. double c2 = offset[angle + 40];
  404. double c3 = offset[angle + 80];
  405. t1 = n < 0x40 ? 0 : n < 0xc0 ? (n - 0x40) * 0x20 : 0xfff;
  406. t2 = n < 0xe0 ? 0 : (n - 0xe0) * 0x80;
  407. t3 = n < 0x40 ? n * 0x40 : 0xfff;
  408. r[n] = (c1 * t1 + c2 * t2 + c3 * t3) / 4;
  409. g[n] = (c1 * t2 + c2 * t3 + c3 * t1) / 4;
  410. b[n] = (c1 * t3 + c2 * t1 + c3 * t2) / 4;
  411. }
  412. /* Set the palette */
  413. caca_set_dither_palette(caca_dither, r, g, b, a);
  414. /* Silly paths for our balls */
  415. for(n = 0; n < METABALLS; n++)
  416. {
  417. float u = di[n] * i + dj[n] * j + dk[n] * sin(di[n] * k);
  418. float v = dd[n] + di[n] * j + dj[n] * k + dk[n] * sin(dk[n] * i);
  419. u = sin(i + u * 2.1) * (1.0 + sin(u));
  420. v = sin(j + v * 1.9) * (1.0 + sin(v));
  421. x[n] = (XSIZ - METASIZE) / 2 + u * (XSIZ - METASIZE) / 4;
  422. y[n] = (YSIZ - METASIZE) / 2 + v * (YSIZ - METASIZE) / 4;
  423. }
  424. i += 0.011;
  425. j += 0.017;
  426. k += 0.019;
  427. memset(screen, 0, XSIZ * YSIZ);
  428. for(n = 0; n < METABALLS; n++)
  429. draw_ball(screen, x[n], y[n]);
  430. break;
  431. case RENDER:
  432. caca_dither_bitmap(cv, 0, 0,
  433. caca_get_canvas_width(cv),
  434. caca_get_canvas_height(cv),
  435. caca_dither, screen + (METASIZE / 2) * (1 + XSIZ));
  436. break;
  437. case FREE:
  438. free(screen);
  439. caca_free_dither(caca_dither);
  440. break;
  441. }
  442. }
  443. static void create_ball(void)
  444. {
  445. int x, y;
  446. float distance;
  447. for(y = 0; y < METASIZE; y++)
  448. for(x = 0; x < METASIZE; x++)
  449. {
  450. distance = ((METASIZE/2) - x) * ((METASIZE/2) - x)
  451. + ((METASIZE/2) - y) * ((METASIZE/2) - y);
  452. distance = sqrt(distance) * 64 / METASIZE;
  453. metaball[x + y * METASIZE] = distance > 15 ? 0 : (255 - distance) * 15;
  454. }
  455. }
  456. static void draw_ball(uint8_t *screen, unsigned int bx, unsigned int by)
  457. {
  458. unsigned int color;
  459. unsigned int i, e = 0;
  460. unsigned int b = (by * XSIZ) + bx;
  461. for(i = 0; i < METASIZE * METASIZE; i++)
  462. {
  463. color = screen[b] + metaball[i];
  464. if(color > 255)
  465. color = 255;
  466. screen[b] = color;
  467. if(e == METASIZE)
  468. {
  469. e = 0;
  470. b += XSIZ - METASIZE;
  471. }
  472. b++;
  473. e++;
  474. }
  475. }
  476. /* The moir effect */
  477. #define DISCSIZ (XSIZ*2)
  478. #define DISCTHICKNESS (XSIZ*15/40)
  479. static uint8_t disc[DISCSIZ * DISCSIZ];
  480. static void put_disc(uint8_t *, int, int);
  481. static void draw_line(int, int, char);
  482. void moire(enum action action, caca_canvas_t *cv)
  483. {
  484. static caca_dither_t *dither;
  485. static uint8_t *screen;
  486. static float d[6];
  487. static uint32_t red[256], green[256], blue[256], alpha[256];
  488. int i, x, y;
  489. switch(action)
  490. {
  491. case PREPARE:
  492. /* Fill various tables */
  493. for(i = 0 ; i < 256; i++)
  494. red[i] = green[i] = blue[i] = alpha[i] = 0;
  495. for(i = 0; i < 6; i++)
  496. d[i] = ((float)caca_rand(50, 70)) / 1000.0;
  497. red[0] = green[0] = blue[0] = 0x777;
  498. red[1] = green[1] = blue[1] = 0xfff;
  499. /* Fill the circle */
  500. for(i = DISCSIZ * 2; i > 0; i -= DISCTHICKNESS)
  501. {
  502. int t, dx, dy;
  503. for(t = 0, dx = 0, dy = i; dx <= dy; dx++)
  504. {
  505. draw_line(dx / 3, dy / 3, (i / DISCTHICKNESS) % 2);
  506. draw_line(dy / 3, dx / 3, (i / DISCTHICKNESS) % 2);
  507. t += t > 0 ? dx - dy-- : dx;
  508. }
  509. }
  510. break;
  511. case INIT:
  512. screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
  513. dither = caca_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
  514. break;
  515. case UPDATE:
  516. memset(screen, 0, XSIZ * YSIZ);
  517. /* Set the palette */
  518. red[0] = 0.5 * (1 + sin(d[0] * (frame + 1000))) * 0xfff;
  519. green[0] = 0.5 * (1 + cos(d[1] * frame)) * 0xfff;
  520. blue[0] = 0.5 * (1 + cos(d[2] * (frame + 3000))) * 0xfff;
  521. red[1] = 0.5 * (1 + sin(d[3] * (frame + 2000))) * 0xfff;
  522. green[1] = 0.5 * (1 + cos(d[4] * frame + 5.0)) * 0xfff;
  523. blue[1] = 0.5 * (1 + cos(d[5] * (frame + 4000))) * 0xfff;
  524. caca_set_dither_palette(dither, red, green, blue, alpha);
  525. /* Draw circles */
  526. x = cos(d[0] * (frame + 1000)) * 128.0 + (XSIZ / 2);
  527. y = sin(0.11 * frame) * 128.0 + (YSIZ / 2);
  528. put_disc(screen, x, y);
  529. x = cos(0.13 * frame + 2.0) * 64.0 + (XSIZ / 2);
  530. y = sin(d[1] * (frame + 2000)) * 64.0 + (YSIZ / 2);
  531. put_disc(screen, x, y);
  532. break;
  533. case RENDER:
  534. caca_dither_bitmap(cv, 0, 0,
  535. caca_get_canvas_width(cv),
  536. caca_get_canvas_height(cv),
  537. dither, screen);
  538. break;
  539. case FREE:
  540. free(screen);
  541. caca_free_dither(dither);
  542. break;
  543. }
  544. }
  545. static void put_disc(uint8_t *screen, int x, int y)
  546. {
  547. char *src = ((char*)disc) + (DISCSIZ / 2 - x) + (DISCSIZ / 2 - y) * DISCSIZ;
  548. int i, j;
  549. for(j = 0; j < YSIZ; j++)
  550. for(i = 0; i < XSIZ; i++)
  551. {
  552. screen[i + XSIZ * j] ^= src[i + DISCSIZ * j];
  553. }
  554. }
  555. static void draw_line(int x, int y, char color)
  556. {
  557. if(x == 0 || y == 0 || y > DISCSIZ / 2)
  558. return;
  559. if(x > DISCSIZ / 2)
  560. x = DISCSIZ / 2;
  561. memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) - y),
  562. color, 2 * x - 1);
  563. memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) + y - 1),
  564. color, 2 * x - 1);
  565. }
  566. /* Langton ant effect */
  567. #define ANTS 15
  568. #define ITER 2
  569. void langton(enum action action, caca_canvas_t *cv)
  570. {
  571. static char gradient[] =
  572. {
  573. ' ', ' ', '.', '.', ':', ':', 'x', 'x',
  574. 'X', 'X', '&', '&', 'W', 'W', '@', '@',
  575. };
  576. static int steps[][2] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
  577. static uint8_t *screen;
  578. static int width, height;
  579. static int ax[ANTS], ay[ANTS], dir[ANTS];
  580. int i, a, x, y;
  581. switch(action)
  582. {
  583. case PREPARE:
  584. width = caca_get_canvas_width(cv);
  585. height = caca_get_canvas_height(cv);
  586. for(i = 0; i < ANTS; i++)
  587. {
  588. ax[i] = caca_rand(0, width);
  589. ay[i] = caca_rand(0, height);
  590. dir[i] = caca_rand(0, 4);
  591. }
  592. break;
  593. case INIT:
  594. screen = malloc(width * height);
  595. memset(screen, 0, width * height);
  596. break;
  597. case UPDATE:
  598. for(i = 0; i < ITER; i++)
  599. {
  600. for(x = 0; x < width * height; x++)
  601. {
  602. uint8_t p = screen[x];
  603. if((p & 0x0f) > 1)
  604. screen[x] = p - 1;
  605. }
  606. for(a = 0; a < ANTS; a++)
  607. {
  608. uint8_t p = screen[ax[a] + width * ay[a]];
  609. if(p & 0x0f)
  610. {
  611. dir[a] = (dir[a] + 1) % 4;
  612. screen[ax[a] + width * ay[a]] = a << 4;
  613. }
  614. else
  615. {
  616. dir[a] = (dir[a] + 3) % 4;
  617. screen[ax[a] + width * ay[a]] = (a << 4) | 0x0f;
  618. }
  619. ax[a] = (width + ax[a] + steps[dir[a]][0]) % width;
  620. ay[a] = (height + ay[a] + steps[dir[a]][1]) % height;
  621. }
  622. }
  623. break;
  624. case RENDER:
  625. for(y = 0; y < height; y++)
  626. {
  627. for(x = 0; x < width; x++)
  628. {
  629. uint8_t p = screen[x + width * y];
  630. if(p & 0x0f)
  631. caca_set_color_ansi(cv, CACA_WHITE, p >> 4);
  632. else
  633. caca_set_color_ansi(cv, CACA_BLACK, CACA_BLACK);
  634. caca_put_char(cv, x, y, gradient[p & 0x0f]);
  635. }
  636. }
  637. break;
  638. case FREE:
  639. free(screen);
  640. break;
  641. }
  642. }
  643. /* Matrix effect */
  644. #define MAXDROPS 500
  645. #define MINLEN 15
  646. #define MAXLEN 30
  647. void matrix(enum action action, caca_canvas_t *cv)
  648. {
  649. static struct drop
  650. {
  651. int x, y, speed, len;
  652. char str[MAXLEN];
  653. }
  654. drop[MAXDROPS];
  655. int w, h, i, j;
  656. switch(action)
  657. {
  658. case PREPARE:
  659. for(i = 0; i < MAXDROPS; i++)
  660. {
  661. drop[i].x = caca_rand(0, 1000);
  662. drop[i].y = caca_rand(0, 1000);
  663. drop[i].speed = 5 + caca_rand(0, 30);
  664. drop[i].len = MINLEN + caca_rand(0, (MAXLEN - MINLEN));
  665. for(j = 0; j < MAXLEN; j++)
  666. drop[i].str[j] = caca_rand('0', 'z');
  667. }
  668. break;
  669. case INIT:
  670. break;
  671. case UPDATE:
  672. w = caca_get_canvas_width(cv);
  673. h = caca_get_canvas_height(cv);
  674. for(i = 0; i < MAXDROPS && i < (w * h / 32); i++)
  675. {
  676. drop[i].y += drop[i].speed;
  677. if(drop[i].y > 1000)
  678. {
  679. drop[i].y -= 1000;
  680. drop[i].x = caca_rand(0, 1000);
  681. }
  682. }
  683. break;
  684. case RENDER:
  685. w = caca_get_canvas_width(cv);
  686. h = caca_get_canvas_height(cv);
  687. caca_set_color_ansi(cv, CACA_BLACK, CACA_BLACK);
  688. caca_clear_canvas(cv);
  689. for(i = 0; i < MAXDROPS && i < (w * h / 32); i++)
  690. {
  691. int x, y;
  692. x = drop[i].x * w / 1000 / 2 * 2;
  693. y = drop[i].y * (h + MAXLEN) / 1000;
  694. for(j = 0; j < drop[i].len; j++)
  695. {
  696. unsigned int fg;
  697. if(j < 2)
  698. fg = CACA_WHITE;
  699. else if(j < drop[i].len / 4)
  700. fg = CACA_LIGHTGREEN;
  701. else if(j < drop[i].len * 4 / 5)
  702. fg = CACA_GREEN;
  703. else
  704. fg = CACA_DARKGRAY;
  705. caca_set_color_ansi(cv, fg, CACA_BLACK);
  706. caca_put_char(cv, x, y - j,
  707. drop[i].str[(y - j) % drop[i].len]);
  708. }
  709. }
  710. break;
  711. case FREE:
  712. break;
  713. }
  714. }
  715. /* Rotozoom effect */
  716. #define TEXTURE_SIZE 256
  717. #define TABLE_SIZE 65536
  718. /* 24:8 Fixed point stuff */
  719. #define PRECISION 8
  720. #define FMUL(a, b) (((a)*(b))>>PRECISION)
  721. #define TOFIX(d) ((int)( (d)*(double)(1<<PRECISION) ))
  722. #define TOINT(a) (a>>PRECISION);
  723. #include "texture.h"
  724. void rotozoom(enum action action, caca_canvas_t *canvas)
  725. {
  726. static uint32_t screen[XSIZ * YSIZ];
  727. static int cos_tab[TABLE_SIZE], sin_tab[TABLE_SIZE];
  728. static int y_tab[TEXTURE_SIZE];
  729. static caca_dither_t *dither;
  730. uint32_t *p;
  731. static int alphaF, tF;
  732. int scaleF;
  733. /* register is quite a bad idea on CISC, but not on RISC */
  734. register unsigned int x, y;
  735. register unsigned int xxF, yyF, uF, vF, uF_, vF_;
  736. register unsigned int vu, vv;
  737. switch(action)
  738. {
  739. case PREPARE:
  740. for(x = 0; x < TABLE_SIZE; x++)
  741. {
  742. cos_tab[x] = TOFIX(cos(x * (360.0f / (float)TABLE_SIZE)));
  743. sin_tab[x] = TOFIX(sin(x * (360.0f / (float)TABLE_SIZE)));
  744. }
  745. for(x = 0; x < TEXTURE_SIZE; x++)
  746. y_tab[x] = x * TEXTURE_SIZE; /* start of lines offsets */
  747. break;
  748. case INIT:
  749. dither = caca_create_dither(32, XSIZ, YSIZ, XSIZ * 4,
  750. 0x00FF0000,
  751. 0x0000FF00,
  752. 0x000000FF,
  753. 0x00000000);
  754. break;
  755. case UPDATE:
  756. alphaF += 4;
  757. tF += 3;
  758. scaleF = FMUL(sin_tab[tF & 0xFFFF], TOFIX(3)) + (TOFIX(4));
  759. xxF = FMUL(cos_tab[(alphaF) & 0xFFFF], scaleF);
  760. yyF = FMUL(sin_tab[(alphaF) & 0xFFFF], scaleF);
  761. uF = vF = 0;
  762. uF_ = vF_ = 0;
  763. p = screen;
  764. for(y = YSIZ; y--;)
  765. {
  766. for(x = XSIZ; x--;)
  767. {
  768. uF += xxF;
  769. vF += yyF;
  770. vu = TOINT(uF);
  771. vv = TOINT(vF);
  772. vu &= 0xFF; /* ARM doesn't like */
  773. vv &= 0xFF; /* chars as local vars */
  774. *p++ = texture256x256[vu + y_tab[vv]];
  775. }
  776. uF = uF_ -= yyF;
  777. vF = vF_ += xxF;
  778. }
  779. break;
  780. case RENDER:
  781. caca_dither_bitmap(canvas, 0, 0,
  782. caca_get_canvas_width(canvas),
  783. caca_get_canvas_height(canvas),
  784. dither, screen);
  785. break;
  786. case FREE:
  787. caca_free_dither(dither);
  788. break;
  789. }
  790. }