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

Last change on this file since 3225 was 2821, checked in by Sam Hocevar, 12 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
RevLine 
[333]1/*
[1023]2 *  cacademo      various demo effects for libcaca
[769]3 *  Copyright (c) 1998 Michele Bini <mibin@tin.it>
[1032]4 *                2003-2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2004-2006 Sam Hocevar <sam@zoy.org>
[333]6 *                All Rights Reserved
7 *
8 *  $Id: cacademo.c 2821 2008-09-27 13:12:46Z sam $
9 *
[1462]10 *  This program is free software. It comes without any warranty, to
[1452]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
[522]14 *  http://sam.zoy.org/wtfpl/COPYING for more details.
[333]15 */
16
17#include "config.h"
18
[581]19#if !defined(__KERNEL__)
[703]20#   include <stdio.h>
[1027]21#   include <stdlib.h>
[1023]22#   include <string.h>
[581]23#   include <math.h>
24#   ifndef M_PI
25#       define M_PI 3.14159265358979323846
26#   endif
[333]27#endif
28
29#include "caca.h"
30
[1032]31enum action { PREPARE, INIT, UPDATE, RENDER, FREE };
[333]32
[2821]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 *);
[333]40
[2821]41void (*fn[])(enum action, caca_canvas_t *) =
[1027]42{
43    plasma,
44    metaballs,
45    moire,
[1766]46    /*langton,*/
[1030]47    matrix,
[1766]48    rotozoom,
[1027]49};
[1032]50#define DEMOS (sizeof(fn)/sizeof(*fn))
[333]51
[2821]52#define DEMO_FRAMES caca_rand(500, 1000)
[1032]53#define TRANSITION_FRAMES 40
54
[1884]55#define TRANSITION_COUNT  5
[1034]56#define TRANSITION_CIRCLE 0
57#define TRANSITION_STAR   1
[1757]58#define TRANSITION_SQUARE 2
[1884]59#define TRANSITION_VLINES 3
60#define TRANSITION_HLINES 4
[1034]61
[1027]62/* Common macros for dither-based demos */
63#define XSIZ 256
64#define YSIZ 256
[333]65
[1027]66/* Global variables */
67static int frame = 0;
[1023]68
69int main(int argc, char **argv)
[333]70{
[1027]71    static caca_display_t *dp;
[2821]72    static caca_canvas_t *frontcv, *backcv, *mask;
[1023]73
[2304]74    int demo, next = -1, paused = 0, next_transition = DEMO_FRAMES;
[1032]75    unsigned int i;
[2821]76    int tmode = caca_rand(0, TRANSITION_COUNT);
[1032]77
[1027]78    /* Set up two canvases, a mask, and attach a display to the front one */
[2821]79    frontcv = caca_create_canvas(0, 0);
80    backcv = caca_create_canvas(0, 0);
81    mask = caca_create_canvas(0, 0);
[1023]82
[1027]83    dp = caca_create_display(frontcv);
[811]84    if(!dp)
[524]85        return 1;
[333]86
[2821]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));
[1027]91
[964]92    caca_set_display_time(dp, 20000);
[333]93
[1032]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 */
[2821]99    demo = caca_rand(0, DEMOS);
[1032]100    fn[demo](INIT, frontcv);
[703]101
[1034]102    for(;;)
[333]103    {
[1032]104        /* Handle events */
[777]105        caca_event_t ev;
[1032]106        while(caca_get_event(dp, CACA_EVENT_KEY_PRESS
107                                  | CACA_EVENT_QUIT, &ev, 0))
[370]108        {
[2049]109            if(caca_get_event_type(&ev) == CACA_EVENT_QUIT)
[1032]110                goto end;
111
[2049]112            switch(caca_get_event_key_ch(&ev))
[681]113            {
[1032]114                case CACA_KEY_ESCAPE:
[1386]115                case CACA_KEY_CTRL_C:
116                case CACA_KEY_CTRL_Z:
[1032]117                    goto end;
118                case ' ':
[2304]119                    paused = !paused;
[1032]120                    break;
[1226]121                case '\r':
[1032]122                    if(next == -1)
123                        next_transition = frame;
124                    break;
[681]125            }
[370]126        }
127
[1032]128        /* Resize the spare canvas, just in case the main one changed */
[2821]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));
[1032]133
[2304]134        if(paused)
135            goto _paused;
[377]136
[1032]137        /* Update demo's data */
138        fn[demo](UPDATE, frontcv);
139
140        /* Handle transitions */
141        if(frame == next_transition)
142        {
[2821]143            next = caca_rand(0, DEMOS);
[1034]144            if(next == demo)
[1032]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;
[2821]154            tmode = caca_rand(0, TRANSITION_COUNT);
[1032]155        }
156
157        if(next != -1)
158            fn[next](UPDATE, backcv);
159
[1027]160        frame++;
[2304]161_paused:
[1032]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);
[2821]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);
[1041]172            transition(mask, tmode,
[1042]173                       100 * (frame - next_transition) / TRANSITION_FRAMES);
[2821]174            caca_blit(frontcv, 0, 0, backcv, mask);
[1032]175        }
176
[2821]177        caca_set_color_ansi(frontcv, CACA_WHITE, CACA_BLUE);
[1152]178        if(frame < 100)
[2821]179            caca_put_str(frontcv, caca_get_canvas_width(frontcv) - 30,
180                                   caca_get_canvas_height(frontcv) - 2,
[1347]181                                   " -=[ Powered by libcaca ]=- ");
[1027]182        caca_refresh_display(dp);
183    }
184end:
[1032]185    if(next != -1)
186        fn[next](FREE, frontcv);
187    fn[demo](FREE, frontcv);
[1027]188
189    caca_free_display(dp);
[2821]190    caca_free_canvas(mask);
191    caca_free_canvas(backcv);
192    caca_free_canvas(frontcv);
[1027]193
194    return 0;
195}
196
[1034]197/* Transitions */
[2821]198void transition(caca_canvas_t *mask, int tmode, int completed)
[1034]199{
[1038]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
[1757]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
[2821]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;
[1042]229    float angle = (0.0075f * completed * 360) * 3.14 / 180, x, y;
[1037]230    unsigned int i;
[2821]231    int w = caca_get_canvas_width(mask);
232    int h = caca_get_canvas_height(mask);
[1040]233
[1041]234    switch(tmode)
[1034]235    {
[1757]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;
[2821]249            caca_fill_triangle(mask,
[1757]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, '#');
[2821]253            caca_fill_triangle(mask,
[1757]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
[1034]260        case TRANSITION_STAR:
[1037]261            /* Compute rotated coordinates */
[1040]262            for(i = 0; i < (sizeof(star) / sizeof(*star)) / 2; i++)
[1037]263            {
[1043]264                x = star[i * 2];
265                y = star[i * 2 + 1];
[1037]266
[1043]267                star_rot[i * 2] = x * cos(angle) - y * sin(angle);
268                star_rot[i * 2 + 1] = y * cos(angle) + x * sin(angle);
[1037]269            }
270
[1040]271            mulx *= 1.8;
272            muly *= 1.8;
273
274#define DO_TRI(a, b, c) \
[2821]275    caca_fill_triangle(mask, \
[1043]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, \
[1330]278        star_rot[(c)*2] * mulx + w2, star_rot[(c)*2+1] * muly + h2, '#')
[1040]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);
[1034]287            break;
288
289        case TRANSITION_CIRCLE:
[2821]290            caca_fill_ellipse(mask, w2, h2, mulx, muly, '#');
[1034]291            break;
292
[1884]293        case TRANSITION_VLINES:
294            for(i = 0; i < 8; i++)
295            {
[2254]296                int z = ((i & 1) ? w : (-w)/2) * (100 - completed) / 100;
[2821]297                caca_fill_box(mask, i * w / 8, z ,  (w / 8) + 1, z + h, '#');
[1884]298            }
299            break;
300
301        case TRANSITION_HLINES:
[2254]302
[1884]303            for(i = 0; i < 6; i++)
304            {
[2254]305                int z = ((i & 1) ? w : (-w)/2) * (100 - completed) / 100;
[2821]306                caca_fill_box(mask, z, i * h / 6, z + w, (h / 6) + 1, '#');
[1884]307            }
308            break;
[1034]309    }
310}
311
[1027]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
[2821]320void plasma(enum action action, caca_canvas_t *cv)
[1027]321{
[2821]322    static caca_dither_t *dither;
[1027]323    static uint8_t *screen;
[2399]324    static uint32_t red[256], green[256], blue[256], alpha[256];
[1027]325    static double r[3], R[6];
326
327    int i, x, y;
328
329    switch(action)
330    {
[1032]331    case PREPARE:
[1027]332        /* Fill various tables */
[333]333        for(i = 0 ; i < 256; i++)
[1027]334            red[i] = green[i] = blue[i] = alpha[i] = 0;
335
336        for(i = 0; i < 3; i++)
[2821]337            r[i] = (double)(caca_rand(1, 1000)) / 60000 * M_PI;
[1027]338
339        for(i = 0; i < 6; i++)
[2821]340            R[i] = (double)(caca_rand(1, 1000)) / 10000;
[1027]341
342        for(y = 0 ; y < TABLEY ; y++)
343            for(x = 0 ; x < TABLEX ; x++)
[333]344        {
[1027]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        }
[1032]351        break;
[1027]352
[1032]353    case INIT:
354        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
[2821]355        dither = caca_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
[1027]356        break;
357
358    case UPDATE:
359        for(i = 0 ; i < 256; i++)
360        {
[333]361            double z = ((double)i) / 256 * 6 * M_PI;
362
[655]363            red[i] = (1.0 + sin(z + r[1] * frame)) / 2 * 0xfff;
[1387]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;
[333]366        }
367
368        /* Set the palette */
[2821]369        caca_set_dither_palette(dither, red, green, blue, alpha);
[333]370
[377]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);
[1027]378        break;
[1030]379
[1032]380    case RENDER:
[2821]381        caca_dither_bitmap(cv, 0, 0,
382                            caca_get_canvas_width(cv),
383                            caca_get_canvas_height(cv),
[734]384                            dither, screen);
[1027]385        break;
[1030]386
[1027]387    case FREE:
388        free(screen);
[2821]389        caca_free_dither(dither);
[1027]390        break;
[333]391    }
392}
393
[1027]394static void do_plasma(uint8_t *pixels, double x_1, double y_1,
[333]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;
[1027]404    uint8_t * t1 = table + X1 + Y1 * TABLEX,
405            * t2 = table + X2 + Y2 * TABLEX,
406            * t3 = table + X3 + Y3 * TABLEX;
[333]407
408    for(y = 0; y < YSIZ; y++)
409    {
410        unsigned int x;
[1027]411        uint8_t * tmp = pixels + y * YSIZ;
[333]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
[1027]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];
[1023]423
[1027]424static void create_ball(void);
425static void draw_ball(uint8_t *, unsigned int, unsigned int);
[1023]426
[2821]427void metaballs(enum action action, caca_canvas_t *cv)
[1027]428{
[2821]429    static caca_dither_t *caca_dither;
[1027]430    static uint8_t *screen;
[2399]431    static uint32_t r[256], g[256], b[256], a[256];
[1027]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];
[1387]436    static unsigned int angleoff;
[1023]437
[1038]438    int n, angle;
[1023]439
[1027]440    switch(action)
441    {
[1032]442    case PREPARE:
[1027]443        /* Make the palette eatable by libcaca */
[1038]444        for(n = 0; n < 256; n++)
445            r[n] = g[n] = b[n] = a[n] = 0x0;
[1027]446        r[255] = g[255] = b[255] = 0xfff;
[1023]447
[1027]448        /* Generate ball sprite */
449        create_ball();
[1023]450
[1038]451        for(n = 0; n < METABALLS; n++)
[1023]452        {
[2821]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;
[1023]457        }
458
[2821]459        angleoff = caca_rand(0, 360);
[1387]460
[1038]461        for(n = 0; n < 360 + 80; n++)
462            offset[n] = 1.0 + sin((double)(n * M_PI / 60));
[1027]463        break;
[1023]464
[1032]465    case INIT:
466        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
[2821]467        /* Create a libcaca dither smaller than our pixel buffer, so that we
[1032]468         * display only the interesting part of it */
[2821]469        caca_dither = caca_create_dither(8, XSIZ - METASIZE, YSIZ - METASIZE,
[1032]470                                           XSIZ, 0, 0, 0, 0);
471        break;
472
[1027]473    case UPDATE:
[1387]474        angle = (frame + angleoff) % 360;
[1023]475
476        /* Crop the palette */
[1038]477        for(n = CROPBALL; n < 255; n++)
[1023]478        {
479            int t1, t2, t3;
[1027]480            double c1 = offset[angle];
481            double c2 = offset[angle + 40];
482            double c3 = offset[angle + 80];
[1023]483
[1038]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;
[1023]487
[1038]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;
[1023]491        }
492
493        /* Set the palette */
[2821]494        caca_set_dither_palette(caca_dither, r, g, b, a);
[1023]495
496        /* Silly paths for our balls */
[1038]497        for(n = 0; n < METABALLS; n++)
[1023]498        {
[1038]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);
[1023]501            u = sin(i + u * 2.1) * (1.0 + sin(u));
502            v = sin(j + v * 1.9) * (1.0 + sin(v));
[1038]503            x[n] = (XSIZ - METASIZE) / 2 + u * (XSIZ - METASIZE) / 4;
504            y[n] = (YSIZ - METASIZE) / 2 + v * (YSIZ - METASIZE) / 4;
[1023]505        }
506
507        i += 0.011;
508        j += 0.017;
509        k += 0.019;
510
511        memset(screen, 0, XSIZ * YSIZ);
512
[1038]513        for(n = 0; n < METABALLS; n++)
514            draw_ball(screen, x[n], y[n]);
[1027]515        break;
[1023]516
[1032]517    case RENDER:
[2821]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));
[1027]522        break;
[1023]523
[1027]524    case FREE:
525        free(screen);
[2821]526        caca_free_dither(caca_dither);
[1027]527        break;
[1023]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
[1027]546static void draw_ball(uint8_t *screen, unsigned int bx, unsigned int by)
[1023]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
[1027]570/* The moiré effect */
571#define DISCSIZ (XSIZ*2)
572#define DISCTHICKNESS (XSIZ*15/40)
573static uint8_t disc[DISCSIZ * DISCSIZ];
[1023]574
[1027]575static void put_disc(uint8_t *, int, int);
576static void draw_line(int, int, char);
[1023]577
[2821]578void moire(enum action action, caca_canvas_t *cv)
[1027]579{
[2821]580    static caca_dither_t *dither;
[1027]581    static uint8_t *screen;
[1387]582    static float d[6];
[2399]583    static uint32_t red[256], green[256], blue[256], alpha[256];
[1023]584
[1027]585    int i, x, y;
[1023]586
[1027]587    switch(action)
588    {
[1032]589    case PREPARE:
[1027]590        /* Fill various tables */
591        for(i = 0 ; i < 256; i++)
592            red[i] = green[i] = blue[i] = alpha[i] = 0;
[1023]593
[1387]594        for(i = 0; i < 6; i++)
[2821]595            d[i] = ((float)caca_rand(50, 70)) / 1000.0;
[1387]596
[1027]597        red[0] = green[0] = blue[0] = 0x777;
598        red[1] = green[1] = blue[1] = 0xfff;
[1023]599
[1027]600        /* Fill the circle */
601        for(i = DISCSIZ * 2; i > 0; i -= DISCTHICKNESS)
[1038]602        {
603            int t, dx, dy;
[1023]604
[1038]605            for(t = 0, dx = 0, dy = i; dx <= dy; dx++)
606            {
[1387]607                draw_line(dx / 3, dy / 3, (i / DISCTHICKNESS) % 2);
608                draw_line(dy / 3, dx / 3, (i / DISCTHICKNESS) % 2);
[1757]609
[1038]610                t += t > 0 ? dx - dy-- : dx;
611            }
612        }
613
[1032]614        break;
615
616    case INIT:
617        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
[2821]618        dither = caca_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
[1027]619        break;
[1023]620
[1027]621    case UPDATE:
[1023]622        memset(screen, 0, XSIZ * YSIZ);
623
624        /* Set the palette */
[1387]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;
[1023]628
[1387]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;
[1023]632
[2821]633        caca_set_dither_palette(dither, red, green, blue, alpha);
[1023]634
635        /* Draw circles */
[1387]636        x = cos(d[0] * (frame + 1000)) * 128.0 + (XSIZ / 2);
[1023]637        y = sin(0.11 * frame) * 128.0 + (YSIZ / 2);
[1027]638        put_disc(screen, x, y);
[1023]639
640        x = cos(0.13 * frame + 2.0) * 64.0 + (XSIZ / 2);
[1387]641        y = sin(d[1] * (frame + 2000)) * 64.0 + (YSIZ / 2);
[1027]642        put_disc(screen, x, y);
643        break;
[1023]644
[1032]645    case RENDER:
[2821]646        caca_dither_bitmap(cv, 0, 0,
647                            caca_get_canvas_width(cv),
648                            caca_get_canvas_height(cv),
[1023]649                            dither, screen);
[1027]650        break;
651
652    case FREE:
653        free(screen);
[2821]654        caca_free_dither(dither);
[1027]655        break;
[1023]656    }
657}
658
[1027]659static void put_disc(uint8_t *screen, int x, int y)
[1023]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
[1030]685/* Langton ant effect */
686#define ANTS 15
687#define ITER 2
688
[2821]689void langton(enum action action, caca_canvas_t *cv)
[1030]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    {
[1032]705    case PREPARE:
[2821]706        width = caca_get_canvas_width(cv);
707        height = caca_get_canvas_height(cv);
[1030]708        for(i = 0; i < ANTS; i++)
709        {
[2821]710            ax[i] = caca_rand(0, width);
711            ay[i] = caca_rand(0, height);
712            dir[i] = caca_rand(0, 4);
[1030]713        }
714        break;
715
[1032]716    case INIT:
717        screen = malloc(width * height);
718        memset(screen, 0, width * height);
719        break;
720
[1030]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;
[1034]744                }
[1030]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
[1032]751    case RENDER:
[1030]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)
[2821]759                    caca_set_color_ansi(cv, CACA_WHITE, p >> 4);
[1030]760                else
[2821]761                    caca_set_color_ansi(cv, CACA_BLACK, CACA_BLACK);
762                caca_put_char(cv, x, y, gradient[p & 0x0f]);
[1030]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
[2821]778void matrix(enum action action, caca_canvas_t *cv)
[1030]779{
[1038]780    static struct drop
781    {
782        int x, y, speed, len;
783        char str[MAXLEN];
784    }
785    drop[MAXDROPS];
[1030]786
[1038]787    int w, h, i, j;
[1030]788
789    switch(action)
790    {
[1032]791    case PREPARE:
[1030]792        for(i = 0; i < MAXDROPS; i++)
793        {
[2821]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));
[1030]798            for(j = 0; j < MAXLEN; j++)
[2821]799                drop[i].str[j] = caca_rand('0', 'z');
[1030]800        }
801        break;
802
[1032]803    case INIT:
804        break;
805
[1030]806    case UPDATE:
[2821]807        w = caca_get_canvas_width(cv);
808        h = caca_get_canvas_height(cv);
[1030]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;
[2821]816                drop[i].x = caca_rand(0, 1000);
[1030]817            }
818        }
819        break;
820
[1032]821    case RENDER:
[2821]822        w = caca_get_canvas_width(cv);
823        h = caca_get_canvas_height(cv);
[1038]824
[2821]825        caca_set_color_ansi(cv, CACA_BLACK, CACA_BLACK);
826        caca_clear_canvas(cv);
[1030]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)
[2821]840                    fg = CACA_WHITE;
[1030]841                else if(j < drop[i].len / 4)
[2821]842                    fg = CACA_LIGHTGREEN;
[1030]843                else if(j < drop[i].len * 4 / 5)
[2821]844                    fg = CACA_GREEN;
[1030]845                else
[2821]846                    fg = CACA_DARKGRAY;
847                caca_set_color_ansi(cv, fg, CACA_BLACK);
[1030]848
[2821]849                caca_put_char(cv, x, y - j,
[1347]850                               drop[i].str[(y - j) % drop[i].len]);
[1030]851            }
852        }
853        break;
854
855    case FREE:
856        break;
857    }
858}
859
[1783]860/* Rotozoom effect */
[1766]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
[2821]873void rotozoom(enum action action, caca_canvas_t *canvas)
[1766]874{
[1783]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
[2821]879    static caca_dither_t *dither;
[1783]880    static uint32_t *texture;
881    uint32_t *p;
[1766]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_;
[1783]888    register unsigned int vu, vv;
[1766]889
890    switch(action)
891    {
[1783]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
[1766]904    case INIT:
[2821]905        dither = caca_create_dither(32, XSIZ, YSIZ, XSIZ * 4,
[1766]906                                     0x00FF0000,
907                                     0x0000FF00,
908                                     0x000000FF,
909                                     0x00000000);
[1777]910        break;
[1766]911
912    case UPDATE:
[1783]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);
[1766]918        uF  = vF  = 0;
919        uF_ = vF_ = 0;
[1783]920        p = screen;
[1766]921
[1783]922        for(y = YSIZ; y--;)
923        {
924            for(x = XSIZ; x--;)
925            {
926                uF += xxF;
927                vF += yyF;
[1766]928
929                vu = TOINT(uF);
930                vv = TOINT(vF);
[1783]931                vu &= 0xFF;       /* ARM doesn't like    */
932                vv &= 0xFF;       /* chars as local vars */
[1766]933
[1783]934                *p++ = texture[vu + y_tab[vv]];
935            }
[1766]936
937            uF = uF_ -= yyF;
938            vF = vF_ += xxF;
939        }
940        break;
[1783]941
[1766]942    case RENDER:
[2821]943        caca_dither_bitmap(canvas, 0, 0,
944                            caca_get_canvas_width(canvas),
945                            caca_get_canvas_height(canvas),
[1783]946                            dither, screen);
[1766]947        break;
[1777]948
[1766]949    case FREE:
[2821]950        caca_free_dither(dither);
[1766]951        break;
952    }
[1783]953}
[1766]954
Note: See TracBrowser for help on using the repository browser.