source: libcaca/trunk/src/cacademo.c @ 2821

Last change on this file since 2821 was 2821, checked in by Sam Hocevar, 11 years ago

Starting refactoring to get rid of libcucul. The initial reason for the
split is rendered moot by the plugin system: when enabled, binaries do
not link directly with libX11 or libGL. I hope this is a step towards
more consisteny and clarity.

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