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

Last change on this file since 1027 was 1027, checked in by Sam Hocevar, 14 years ago
  • Factor most of the cacademo code.
  • Property svn:keywords set to Id
File size: 13.5 KB
Line 
1/*
2 *  cacademo      various demo effects for libcaca
3 *  Copyright (c) 1998 Michele Bini <mibin@tin.it>
4 *                2003-2004 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2004 Sam Hocevar <sam@zoy.org>
6 *                All Rights Reserved
7 *
8 *  $Id: cacademo.c 1027 2006-09-16 13:12:11Z sam $
9 *
10 *  This program is free software; you can redistribute it and/or
11 *  modify it under the terms of the Do What The Fuck You Want To
12 *  Public License, Version 2, as published by Sam Hocevar. See
13 *  http://sam.zoy.org/wtfpl/COPYING for more details.
14 */
15
16#include "config.h"
17#include "common.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 "cucul.h"
30#include "caca.h"
31
32enum action { INIT, UPDATE, DRAW, FREE };
33
34void plasma(enum action, cucul_canvas_t *);
35void metaballs(enum action, cucul_canvas_t *);
36void moire(enum action, cucul_canvas_t *);
37
38void (*demo_list[])(enum action, cucul_canvas_t *) =
39{
40    plasma,
41    metaballs,
42    moire,
43};
44
45/* Common macros for dither-based demos */
46#define XSIZ 256
47#define YSIZ 256
48
49/* Global variables */
50static int frame = 0;
51
52int main(int argc, char **argv)
53{
54    static caca_display_t *dp;
55    static cucul_canvas_t *frontcv, *backcv, *mask;
56    int demo = 0, pause = 0;
57
58    /* Set up two canvases, a mask, and attach a display to the front one */
59    frontcv = cucul_create_canvas(0, 0);
60    backcv = cucul_create_canvas(0, 0);
61    mask = cucul_create_canvas(0, 0);
62
63    dp = caca_create_display(frontcv);
64    if(!dp)
65        return 1;
66
67    cucul_set_canvas_size(backcv, cucul_get_canvas_width(frontcv),
68                                  cucul_get_canvas_height(frontcv));
69    cucul_set_canvas_size(mask, cucul_get_canvas_width(frontcv),
70                                cucul_get_canvas_height(frontcv));
71
72    caca_set_display_time(dp, 20000);
73
74    demo = cucul_rand(0, 3);
75
76    demo_list[demo](INIT, NULL);
77
78    for(;;)
79    {
80        caca_event_t ev;
81        if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 0))
82        {
83            switch(ev.data.key.ch)
84            {
85                case CACA_KEY_ESCAPE: goto end;
86                case ' ': pause = !pause;
87            }
88        }
89
90        if(pause)
91            goto paused;
92
93        demo_list[demo](UPDATE, NULL);
94        frame++;
95paused:
96        demo_list[demo](DRAW, frontcv);
97        cucul_set_color(frontcv, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
98        cucul_putstr(frontcv, cucul_get_canvas_width(frontcv) - 30,
99                              cucul_get_canvas_height(frontcv) - 2,
100                              " -=[ Powered by libcaca ]=- ");
101        caca_refresh_display(dp);
102    }
103end:
104    demo_list[demo](FREE, NULL);
105
106    caca_free_display(dp);
107    cucul_free_canvas(mask);
108    cucul_free_canvas(backcv);
109    cucul_free_canvas(frontcv);
110
111    return 0;
112}
113
114/* The plasma effect */
115#define TABLEX (XSIZ * 2)
116#define TABLEY (YSIZ * 2)
117static uint8_t table[TABLEX * TABLEY];
118
119static void do_plasma(uint8_t *,
120                      double, double, double, double, double, double);
121
122void plasma(enum action action, cucul_canvas_t *cv)
123{
124    static cucul_dither_t *dither;
125    static uint8_t *screen;
126    static unsigned int red[256], green[256], blue[256], alpha[256];
127    static double r[3], R[6];
128
129    int i, x, y;
130
131    switch(action)
132    {
133    case INIT:
134        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
135
136        /* Fill various tables */
137        for(i = 0 ; i < 256; i++)
138            red[i] = green[i] = blue[i] = alpha[i] = 0;
139
140        for(i = 0; i < 3; i++)
141            r[i] = (double)(cucul_rand(1, 1000)) / 60000 * M_PI;
142
143        for(i = 0; i < 6; i++)
144            R[i] = (double)(cucul_rand(1, 1000)) / 10000;
145
146        for(y = 0 ; y < TABLEY ; y++)
147            for(x = 0 ; x < TABLEX ; x++)
148        {
149            double tmp = (((double)((x - (TABLEX / 2)) * (x - (TABLEX / 2))
150                                  + (y - (TABLEX / 2)) * (y - (TABLEX / 2))))
151                          * (M_PI / (TABLEX * TABLEX + TABLEY * TABLEY)));
152
153            table[x + y * TABLEX] = (1.0 + sin(12.0 * sqrt(tmp))) * 256 / 6;
154        }
155
156        /* Create a libcucul dither */
157        dither = cucul_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
158        break;
159
160    case UPDATE:
161        for(i = 0 ; i < 256; i++)
162        {
163            double z = ((double)i) / 256 * 6 * M_PI;
164
165            red[i] = (1.0 + sin(z + r[1] * frame)) / 2 * 0xfff;
166            blue[i] = (1.0 + cos(z + r[0] * frame)) / 2 * 0xfff;
167            green[i] = (1.0 + cos(z + r[2] * frame)) / 2 * 0xfff;
168        }
169
170        /* Set the palette */
171        cucul_set_dither_palette(dither, red, green, blue, alpha);
172
173        do_plasma(screen,
174                  (1.0 + sin(((double)frame) * R[0])) / 2,
175                  (1.0 + sin(((double)frame) * R[1])) / 2,
176                  (1.0 + sin(((double)frame) * R[2])) / 2,
177                  (1.0 + sin(((double)frame) * R[3])) / 2,
178                  (1.0 + sin(((double)frame) * R[4])) / 2,
179                  (1.0 + sin(((double)frame) * R[5])) / 2);
180        break;
181    case DRAW:
182        cucul_dither_bitmap(cv, 0, 0,
183                            cucul_get_canvas_width(cv),
184                            cucul_get_canvas_height(cv),
185                            dither, screen);
186        break;
187    case FREE:
188        free(screen);
189        cucul_free_dither(dither);
190        break;
191    }
192}
193
194static void do_plasma(uint8_t *pixels, double x_1, double y_1,
195                      double x_2, double y_2, double x_3, double y_3)
196{
197    unsigned int X1 = x_1 * (TABLEX / 2),
198                 Y1 = y_1 * (TABLEY / 2),
199                 X2 = x_2 * (TABLEX / 2),
200                 Y2 = y_2 * (TABLEY / 2),
201                 X3 = x_3 * (TABLEX / 2),
202                 Y3 = y_3 * (TABLEY / 2);
203    unsigned int y;
204    uint8_t * t1 = table + X1 + Y1 * TABLEX,
205            * t2 = table + X2 + Y2 * TABLEX,
206            * t3 = table + X3 + Y3 * TABLEX;
207
208    for(y = 0; y < YSIZ; y++)
209    {
210        unsigned int x;
211        uint8_t * tmp = pixels + y * YSIZ;
212        unsigned int ty = y * TABLEX, tmax = ty + XSIZ;
213        for(x = 0; ty < tmax; ty++, tmp++)
214            tmp[0] = t1[ty] + t2[ty] + t3[ty];
215    }
216}
217
218/* The metaball effect */
219#define METASIZE (XSIZ/2)
220#define METABALLS 12
221#define CROPBALL 200 /* Colour index where to crop balls */
222static uint8_t metaball[METASIZE * METASIZE];
223
224static void create_ball(void);
225static void draw_ball(uint8_t *, unsigned int, unsigned int);
226
227void metaballs(enum action action, cucul_canvas_t *cv)
228{
229    static cucul_dither_t *cucul_dither;
230    static uint8_t *screen;
231    static unsigned int r[256], g[256], b[256], a[256];
232    static float dd[METABALLS], di[METABALLS], dj[METABALLS], dk[METABALLS];
233    static unsigned int x[METABALLS], y[METABALLS];
234    static float i = 10.0, j = 17.0, k = 11.0;
235    static double offset[360 + 80];
236
237    int p, angle;
238
239    switch(action)
240    {
241    case INIT:
242        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
243
244        /* Make the palette eatable by libcaca */
245        for(p = 0; p < 256; p++)
246            r[p] = g[p] = b[p] = a[p] = 0x0;
247        r[255] = g[255] = b[255] = 0xfff;
248
249        /* Create a libcucul dither smaller than our pixel buffer, so that we
250         * display only the interesting part of it */
251        cucul_dither = cucul_create_dither(8, XSIZ - METASIZE, YSIZ - METASIZE,
252                                           XSIZ, 0, 0, 0, 0);
253        /* Generate ball sprite */
254        create_ball();
255
256        for(p = 0; p < METABALLS; p++)
257        {
258            dd[p] = cucul_rand(0, 100);
259            di[p] = (float)cucul_rand(500, 4000) / 6000.0;
260            dj[p] = (float)cucul_rand(500, 4000) / 6000.0;
261            dk[p] = (float)cucul_rand(500, 4000) / 6000.0;
262        }
263
264        for(p = 0; p < 360 + 80; p++)
265            offset[p] = 1.0 + sin((double)(p * M_PI / 60));
266        break;
267
268    case UPDATE:
269        angle = frame % 360;
270
271        /* Crop the palette */
272        for(p = CROPBALL; p < 255; p++)
273        {
274            int t1, t2, t3;
275            double c1 = offset[angle];
276            double c2 = offset[angle + 40];
277            double c3 = offset[angle + 80];
278
279            t1 = p < 0x40 ? 0 : p < 0xc0 ? (p - 0x40) * 0x20 : 0xfff;
280            t2 = p < 0xe0 ? 0 : (p - 0xe0) * 0x80;
281            t3 = p < 0x40 ? p * 0x40 : 0xfff;
282
283            r[p] = (c1 * t1 + c2 * t2 + c3 * t3) / 4;
284            g[p] = (c1 * t2 + c2 * t3 + c3 * t1) / 4;
285            b[p] = (c1 * t3 + c2 * t1 + c3 * t2) / 4;
286        }
287
288        /* Set the palette */
289        cucul_set_dither_palette(cucul_dither, r, g, b, a);
290
291        /* Silly paths for our balls */
292        for(p = 0; p < METABALLS; p++)
293        {
294            float u = di[p] * i + dj[p] * j + dk[p] * sin(di[p] * k);
295            float v = dd[p] + di[p] * j + dj[p] * k + dk[p] * sin(dk[p] * i);
296            u = sin(i + u * 2.1) * (1.0 + sin(u));
297            v = sin(j + v * 1.9) * (1.0 + sin(v));
298            x[p] = (XSIZ - METASIZE) / 2 + u * (XSIZ - METASIZE) / 4;
299            y[p] = (YSIZ - METASIZE) / 2 + v * (YSIZ - METASIZE) / 4;
300        }
301
302        i += 0.011;
303        j += 0.017;
304        k += 0.019;
305
306        memset(screen, 0, XSIZ * YSIZ);
307
308        /* Here is all the trick. Maybe if you're that
309         * clever you'll understand. */
310        for(p = 0; p < METABALLS; p++)
311            draw_ball(screen, x[p], y[p]);
312        break;
313
314    case DRAW:
315        cucul_dither_bitmap(cv, 0, 0,
316                          cucul_get_canvas_width(cv),
317                          cucul_get_canvas_height(cv),
318                          cucul_dither, screen + (METASIZE / 2) * (1 + XSIZ));
319        break;
320
321    case FREE:
322        free(screen);
323        cucul_free_dither(cucul_dither);
324        break;
325    }
326}
327
328/* Generate ball sprite
329 * You should read the comments, I already wrote that before ... */
330static void create_ball(void)
331{
332    int x, y;
333    float distance;
334
335    for(y = 0; y < METASIZE; y++)
336        for(x = 0; x < METASIZE; x++)
337    {
338        distance = ((METASIZE/2) - x) * ((METASIZE/2) - x)
339                 + ((METASIZE/2) - y) * ((METASIZE/2) - y);
340        distance = sqrt(distance) * 64 / METASIZE;
341        metaball[x + y * METASIZE] = distance > 15 ? 0 : (255 - distance) * 15;
342    }
343}
344
345/* You missed the trick ? */
346static void draw_ball(uint8_t *screen, unsigned int bx, unsigned int by)
347{
348    unsigned int color;
349    unsigned int i, e = 0;
350    unsigned int b = (by * XSIZ) + bx;
351
352    for(i = 0; i < METASIZE * METASIZE; i++)
353    {
354        color = screen[b] + metaball[i];
355
356        if(color > 255)
357            color = 255;
358
359        screen[b] = color;
360        if(e == METASIZE)
361        {
362            e = 0;
363            b += XSIZ - METASIZE;
364        }
365        b++;
366        e++;
367    }
368}
369
370/* The moiré effect */
371#define DISCSIZ (XSIZ*2)
372#define DISCTHICKNESS (XSIZ*15/40)
373static uint8_t disc[DISCSIZ * DISCSIZ];
374
375static void put_disc(uint8_t *, int, int);
376static void draw_disc(int, char);
377static void draw_line(int, int, char);
378
379void moire(enum action action, cucul_canvas_t *cv)
380{
381    static cucul_dither_t *dither;
382    static uint8_t *screen;
383    static unsigned int red[256], green[256], blue[256], alpha[256];
384
385    int i, x, y;
386
387    switch(action)
388    {
389    case INIT:
390        screen = malloc(XSIZ * YSIZ * sizeof(uint8_t));
391
392        /* Fill various tables */
393        for(i = 0 ; i < 256; i++)
394            red[i] = green[i] = blue[i] = alpha[i] = 0;
395
396        red[0] = green[0] = blue[0] = 0x777;
397        red[1] = green[1] = blue[1] = 0xfff;
398
399        /* Fill the circle */
400        for(i = DISCSIZ * 2; i > 0; i -= DISCTHICKNESS)
401            draw_disc(i, (i / DISCTHICKNESS) % 2);
402
403        /* Create a libcucul dither */
404        dither = cucul_create_dither(8, XSIZ, YSIZ, XSIZ, 0, 0, 0, 0);
405        break;
406
407    case UPDATE:
408        memset(screen, 0, XSIZ * YSIZ);
409
410        /* Set the palette */
411        red[0] = 0.5 * (1 + sin(0.05 * frame)) * 0xfff;
412        green[0] = 0.5 * (1 + cos(0.07 * frame)) * 0xfff;
413        blue[0] = 0.5 * (1 + cos(0.06 * frame)) * 0xfff;
414
415        red[1] = 0.5 * (1 + sin(0.07 * frame + 5.0)) * 0xfff;
416        green[1] = 0.5 * (1 + cos(0.06 * frame + 5.0)) * 0xfff;
417        blue[1] = 0.5 * (1 + cos(0.05 * frame + 5.0)) * 0xfff;
418
419        cucul_set_dither_palette(dither, red, green, blue, alpha);
420
421        /* Draw circles */
422        x = cos(0.07 * frame + 5.0) * 128.0 + (XSIZ / 2);
423        y = sin(0.11 * frame) * 128.0 + (YSIZ / 2);
424        put_disc(screen, x, y);
425
426        x = cos(0.13 * frame + 2.0) * 64.0 + (XSIZ / 2);
427        y = sin(0.09 * frame + 1.0) * 64.0 + (YSIZ / 2);
428        put_disc(screen, x, y);
429        break;
430
431    case DRAW:
432        cucul_dither_bitmap(cv, 0, 0,
433                            cucul_get_canvas_width(cv),
434                            cucul_get_canvas_height(cv),
435                            dither, screen);
436        break;
437
438    case FREE:
439        free(screen);
440        cucul_free_dither(dither);
441        break;
442    }
443}
444
445static void put_disc(uint8_t *screen, int x, int y)
446{
447    char *src = ((char*)disc) + (DISCSIZ / 2 - x) + (DISCSIZ / 2 - y) * DISCSIZ;
448    int i, j;
449
450    for(j = 0; j < YSIZ; j++)
451        for(i = 0; i < XSIZ; i++)
452    {
453        screen[i + XSIZ * j] ^= src[i + DISCSIZ * j];
454    }
455}
456
457static void draw_disc(int r, char color)
458{
459    int t, dx, dy;
460
461    for(t = 0, dx = 0, dy = r; dx <= dy; dx++)
462    {
463        draw_line(dx / 3,   dy / 3, color);
464        draw_line(dy / 3,   dx / 3, color);
465
466        t += t > 0 ? dx - dy-- : dx;
467    }
468}
469
470static void draw_line(int x, int y, char color)
471{
472    if(x == 0 || y == 0 || y > DISCSIZ / 2)
473        return;
474
475    if(x > DISCSIZ / 2)
476        x = DISCSIZ / 2;
477
478    memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) - y),
479           color, 2 * x - 1);
480    memset(disc + (DISCSIZ / 2) - x + DISCSIZ * ((DISCSIZ / 2) + y - 1),
481           color, 2 * x - 1);
482}
483
Note: See TracBrowser for help on using the repository browser.