~ubuntu-branches/ubuntu/breezy/xscreensaver/breezy

« back to all changes in this revision

Viewing changes to hacks/intermomentary.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  InterMomentary (dragorn@kismetwireless.net)
 
3
 *  Directly ported code from complexification.net InterMomentary art
 
4
 *  http://www.complexification.net/gallery/machines/interMomentary/applet_l/interMomentary_l.pde
 
5
 *
 
6
 * Intersecting Circles, Instantaneous
 
7
 * J. Tarbell                              + complexification.net
 
8
 * Albuquerque, New Mexico
 
9
 * May, 2004
 
10
 * 
 
11
 * a REAS collaboration for the            + groupc.net
 
12
 * Whitney Museum of American Art ARTPORT  + artport.whitney.org
 
13
 * Robert Hodgin                           + flight404.com
 
14
 * William Ngan                            + metaphorical.net
 
15
 * 
 
16
 *
 
17
 * 1.0  Oct 10 2004  dragorn  Completed first port 
 
18
 *
 
19
 *
 
20
 * Based, of course, on other hacks in:
 
21
 *
 
22
 * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
 
23
 *
 
24
 * Permission to use, copy, modify, distribute, and sell this software and its
 
25
 * documentation for any purpose is hereby granted without fee, provided that
 
26
 * the above copyright notice appear in all copies and that both that
 
27
 * copyright notice and this permission notice appear in supporting
 
28
 * documentation.  No representations are made about the suitability of this
 
29
 * software for any purpose.  It is provided "as is" without express or 
 
30
 * implied warranty.
 
31
 */
 
32
 
 
33
#include "screenhack.h"
 
34
#include <X11/Xutil.h>
 
35
#include <stdio.h>
 
36
#include <sys/time.h>
 
37
 
 
38
#ifndef MAX_WIDTH
 
39
#include <limits.h>
 
40
#define MAX_WIDTH SHRT_MAX
 
41
#endif
 
42
 
 
43
#ifdef TIME_ME
 
44
#include <time.h>
 
45
#endif
 
46
 
 
47
#include <math.h>
 
48
 
 
49
#include "hsv.h"
 
50
 
 
51
/* this program goes faster if some functions are inline.  The following is
 
52
 * borrowed from ifs.c */
 
53
#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
 
54
#undef inline
 
55
#define inline                  /* */
 
56
#endif
 
57
 
 
58
/* Pixel rider */
 
59
typedef struct {
 
60
    float t;
 
61
    float vt;
 
62
    float mycharge;
 
63
} PxRider;
 
64
 
 
65
/* disc of light */
 
66
typedef struct {
 
67
    /* index identifier */
 
68
    int id;
 
69
    /* position */
 
70
    float x, y;
 
71
    /* radius */
 
72
    float r, dr;
 
73
    /* velocity */
 
74
    float vx, vy;
 
75
 
 
76
    /* pixel riders */
 
77
    int numr;
 
78
    PxRider *pxRiders;
 
79
} Disc;
 
80
 
 
81
struct field {
 
82
    unsigned int height;
 
83
    unsigned int width;
 
84
 
 
85
    int initial_discs;
 
86
    Disc *discs;
 
87
    
 
88
    unsigned int num;
 
89
 
 
90
    unsigned int maxrider;
 
91
    unsigned int maxradius;
 
92
 
 
93
    /* color parms */
 
94
    unsigned long fgcolor;
 
95
    unsigned long bgcolor;
 
96
    int visdepth;
 
97
 
 
98
    unsigned int cycles;
 
99
 
 
100
    /* Offscreen image we draw to */
 
101
    Pixmap off_map;
 
102
    unsigned long int *off_alpha;
 
103
};
 
104
 
 
105
static void *xrealloc(void *p, size_t size) {
 
106
    void *ret;
 
107
    if ((ret = realloc(p, size)) == NULL) {
 
108
        fprintf(stderr, "%s: out of memory\n", progname);
 
109
        exit(1);
 
110
    }
 
111
    return ret;
 
112
}
 
113
 
 
114
struct field *init_field(void) {
 
115
    struct field *f = xrealloc(NULL, sizeof(struct field));
 
116
    f->height = 0;
 
117
    f->width = 0;
 
118
    f->initial_discs = 0;
 
119
    f->discs = NULL;
 
120
    f->num = 0;
 
121
    f->maxrider = 0;
 
122
    f->maxradius = 0;
 
123
    f->cycles = 0;
 
124
    f->fgcolor = 0;
 
125
    f->bgcolor = 0;
 
126
    f->off_alpha = NULL;
 
127
    f->visdepth = 0;
 
128
    return f;
 
129
}
 
130
 
 
131
/* Quick-ref to pixels in the alpha map */
 
132
#define ref_pixel(f, x, y)   ((f)->off_alpha[(y) * (f)->width + (x)])
 
133
 
 
134
inline void make_disc(struct field *f, float x, float y, float vx, float vy, float r) {
 
135
    /* Synthesis of Disc::Disc and PxRider::PxRider */
 
136
    Disc *nd;
 
137
    int ix;
 
138
 
 
139
    /* allocate a new disc */
 
140
    f->discs = (Disc *) xrealloc(f->discs, sizeof(Disc) * (f->num + 1));
 
141
 
 
142
    nd = &(f->discs[f->num]);
 
143
 
 
144
    nd->id = f->num++;
 
145
    nd->x = x;
 
146
    nd->y = y;
 
147
    nd->vx = vx;
 
148
    nd->vy = vy;
 
149
    nd->dr = r;
 
150
    nd->r = frand(r) / 3;
 
151
 
 
152
    nd->numr = (frand(r) / 2.62);
 
153
    if (nd->numr > f->maxrider)
 
154
        nd->numr = f->maxrider;
 
155
 
 
156
    nd->pxRiders = NULL;
 
157
    nd->pxRiders = (PxRider *) xrealloc(nd->pxRiders, sizeof(PxRider) * (f->maxrider));
 
158
    for (ix = 0; ix < f->maxrider; ix++) {
 
159
        nd->pxRiders[ix].vt = 0.0;
 
160
        nd->pxRiders[ix].t = frand(M_PI * 2);
 
161
        nd->pxRiders[ix].mycharge = 0;
 
162
    }
 
163
}
 
164
 
 
165
inline void point2rgb(int depth, unsigned long c, unsigned short int *r, 
 
166
                      unsigned short int *g, unsigned short int *b) {
 
167
    switch(depth) {
 
168
        case 32:
 
169
        case 24:
 
170
            *g = (c & 0xff00) >> 8; 
 
171
            *r = (c & 0xff0000) >> 16; 
 
172
            *b = c & 0xff; 
 
173
            break;
 
174
        case 16:
 
175
            *g = ((c >> 5) & 0x3f) << 2;
 
176
            *r = ((c >> 11) & 0x1f) << 3; 
 
177
            *b = (c & 0x1f) << 3; 
 
178
            break;
 
179
        case 15:
 
180
            *g = ((c >> 5) & 0x1f) << 3;
 
181
            *r = ((c >> 10) & 0x1f) << 3;
 
182
            *b = (c & 0x1f) << 3;
 
183
            break;
 
184
    }
 
185
}
 
186
 
 
187
inline unsigned long rgb2point(int depth, unsigned short int r, 
 
188
                               unsigned short int g, unsigned short int b) {
 
189
    unsigned long ret = 0;
 
190
 
 
191
    switch(depth) {
 
192
        case 32:
 
193
            ret = 0xff000000;
 
194
        case 24:
 
195
            ret |= (r << 16) | (g << 8) | b;
 
196
            break;
 
197
        case 16:
 
198
            ret = ((r>>3) << 11) | ((g>>2)<<5) | (b>>3);
 
199
            break;
 
200
        case 15:
 
201
            ret = ((r>>3) << 10) | ((g>>3)<<5) | (b>>3);
 
202
            break;
 
203
    }
 
204
 
 
205
    return ret;
 
206
}
 
207
 
 
208
/* alpha blended point drawing */
 
209
inline unsigned long trans_point(int x1, int y1, unsigned long myc, float a, struct field *f) {
 
210
    if ((x1 >= 0) && (x1 < f->width) && (y1 >= 0) && (y1 < f->height)) {
 
211
        if (a >= 1.0) {
 
212
            ref_pixel(f, x1, y1) = myc;
 
213
        } else {
 
214
            unsigned short int or, og, ob;
 
215
            unsigned short int r, g, b;
 
216
            unsigned short int nr, ng, nb;
 
217
            unsigned long c;
 
218
 
 
219
            c = ref_pixel(f, x1, y1);
 
220
            point2rgb(f->visdepth, c, &or, &og, &ob);
 
221
            point2rgb(f->visdepth, myc, &r, &g, &b);
 
222
 
 
223
            nr = or + (r - or) * a;
 
224
            ng = og + (g - og) * a;
 
225
            nb = ob + (b - ob) * a;
 
226
 
 
227
            c = rgb2point(f->visdepth, nr, ng, nb);
 
228
            ref_pixel(f, x1, y1) = c;
 
229
 
 
230
            return c;
 
231
        }
 
232
    }
 
233
 
 
234
    return 0;
 
235
}
 
236
 
 
237
inline void move_disc(struct field *f, int dnum) {
 
238
    Disc *d = &(f->discs[dnum]);
 
239
 
 
240
    /* add velocity to position */
 
241
    d->x += d->vx;
 
242
    d->y += d->vy;
 
243
 
 
244
    /* bound check */
 
245
    if (d->x + d->r < 0)
 
246
        d->x += f->width + d->r + d->r;
 
247
    if (d->x - d->r > f->width)
 
248
        d->x -= f->width + d->r + d->r;
 
249
    if (d->y + d->r < 0)
 
250
        d->y += f->height + d->r + d->r;
 
251
    if (d->y - d->r > f->height)
 
252
        d->y -= f->height + d->r + d->r;
 
253
 
 
254
    /* increase to destination radius */
 
255
    if (d->r < d->dr)
 
256
        d->r += 0.1;
 
257
}
 
258
 
 
259
inline void draw_glowpoint(Display *dpy, Window window, GC fgc, struct field *f, float px, float py) {
 
260
    int i, j;
 
261
    float a;
 
262
    unsigned long c;
 
263
 
 
264
    for (i =- 2; i < 3; i++) {
 
265
        for (j =- 2; j < 3; j++) {
 
266
            a = 0.8 - i * i * 0.1 - j * j * 0.1;
 
267
 
 
268
            c = trans_point(px+i, py+j, f->fgcolor, a, f);
 
269
            XSetForeground(dpy, fgc, c);
 
270
            XDrawPoint(dpy, window, fgc, px + i, py + j);
 
271
            XSetForeground(dpy, fgc, f->fgcolor);
 
272
        }
 
273
    }
 
274
}
 
275
 
 
276
inline void moverender_rider(Display *dpy, Window window, GC fgc, struct field *f, PxRider *rid, 
 
277
                             float x, float y, float r) {
 
278
    float px, py;
 
279
    unsigned long int c;
 
280
    unsigned short int cr, cg, cb;
 
281
    int ch;
 
282
    double cs, cv;
 
283
 
 
284
    /* add velocity to theta */
 
285
    rid->t = fmod((rid->t + rid->vt + M_PI), (2 * M_PI)) - M_PI;
 
286
    
 
287
    rid->vt += frand(0.002) - 0.001;
 
288
 
 
289
    /* apply friction brakes */
 
290
    if (abs(rid->vt) > 0.02)
 
291
        rid->vt *= 0.9;
 
292
 
 
293
    /* draw */
 
294
    px = x + r * cos(rid->t);
 
295
    py = y + r * sin(rid->t);
 
296
 
 
297
    if ((px < 0) || (px >= f->width) || (py < 0) || (py >= f->height))
 
298
        return;
 
299
 
 
300
    /* max brightness seems to be 0.003845 */
 
301
 
 
302
    c = ref_pixel(f, (int) px, (int) py);
 
303
    point2rgb(f->visdepth, c, &cr, &cg, &cb);
 
304
    rgb_to_hsv(cr, cg, cb, &ch, &cs, &cv);
 
305
 
 
306
    /* guestimated - 40 is 18% of 255, so scale this to 0.0 to 0.003845 */
 
307
    if (cv > 0.0006921) {
 
308
        draw_glowpoint(dpy, window, fgc, f, px, py); 
 
309
 
 
310
        rid->mycharge = 0.003845;
 
311
    } else {
 
312
        rid->mycharge *= 0.98;
 
313
 
 
314
        hsv_to_rgb(ch, cs, rid->mycharge, &cr, &cg, &cb);
 
315
        c = rgb2point(f->visdepth, cr, cg, cb);
 
316
 
 
317
        trans_point(px, py, c, 0.5, f);
 
318
 
 
319
        XSetForeground(dpy, fgc, c);
 
320
        XDrawPoint(dpy, window, fgc, px, py);
 
321
        XSetForeground(dpy, fgc, f->fgcolor);
 
322
    }
 
323
}
 
324
 
 
325
inline void render_disc(Display *dpy, Window window, GC fgc, struct field *f, int dnum) {
 
326
    Disc *di = &(f->discs[dnum]);
 
327
    int n, m;
 
328
    float dx, dy, d;
 
329
    float a, p2x, p2y, h, p3ax, p3ay, p3bx, p3by;
 
330
    unsigned long c;
 
331
 
 
332
    /* Find intersecting points with all ascending discs */
 
333
    for (n = di->id + 1; n < f->num; n++) {
 
334
        dx = f->discs[n].x - di->x;
 
335
        dy = f->discs[n].y - di->y;
 
336
        d = sqrt(dx * dx + dy * dy);
 
337
 
 
338
        /* intersection test */
 
339
        if (d < (f->discs[n].r + di->r)) {
 
340
            /* complete containment test */
 
341
            if (d > abs(f->discs[n].r - di->r)) {
 
342
                /* find solutions */
 
343
                a = (di->r * di->r - f->discs[n].r * f->discs[n].r + d * d) / (2 * d);
 
344
                p2x = di->x + a * (f->discs[n].x - di->x) / d;
 
345
                p2y = di->y + a * (f->discs[n].y - di->y) / d;
 
346
 
 
347
                h = sqrt(di->r * di->r - a * a);
 
348
 
 
349
                p3ax = p2x + h * (f->discs[n].y - di->y) / d;
 
350
                p3ay = p2y - h * (f->discs[n].x - di->x) / d;
 
351
 
 
352
                p3bx = p2x - h * (f->discs[n].y - di->y) / d;
 
353
                p3by = p2y + h * (f->discs[n].x - di->x) / d;
 
354
 
 
355
                /* bounds check */
 
356
                if ((p3ax < 0) || (p3ax >= f->width) || (p3ay < 0) || (p3ay >= f->height) ||
 
357
                    (p3bx < 0) || (p3bx >= f->width) || (p3by < 0) || (p3by >= f->height))
 
358
                    continue;
 
359
                
 
360
                /* p3a and p3b might be identical, ignore this case for now */
 
361
                /* XPutPixel(f->off_map, p3ax, p3ay, f->fgcolor); */
 
362
                c = trans_point(p3ax, p3ay, f->fgcolor, 0.75, f);
 
363
                XSetForeground(dpy, fgc, c);
 
364
                XDrawPoint(dpy, window, fgc, p3ax, p3ay);
 
365
 
 
366
                /* XPutPixel(f->off_map, p3bx, p3by, f->fgcolor); */
 
367
                c = trans_point(p3bx, p3by, f->fgcolor, 0.75, f);
 
368
                XSetForeground(dpy, fgc, c);
 
369
                XDrawPoint(dpy, window, fgc, p3bx, p3by);
 
370
                XSetForeground(dpy, fgc, f->fgcolor);
 
371
            }
 
372
        }
 
373
 
 
374
    }
 
375
 
 
376
    /* Render all the pixel riders */
 
377
    for (m = 0; m < di->numr; m++) {
 
378
        moverender_rider(dpy, window, fgc, f, &(di->pxRiders[m]), 
 
379
                         di->x, di->y, di->r);
 
380
    }
 
381
}
 
382
 
 
383
char *progclass = "InterMomentary";
 
384
 
 
385
char *defaults[] = {
 
386
    ".background: black",
 
387
    ".foreground: white",
 
388
    "*drawDelay: 30000",
 
389
    "*numDiscs: 85",
 
390
    "*maxRiders: 40",
 
391
    "*maxRadius: 100",
 
392
    0
 
393
};
 
394
 
 
395
XrmOptionDescRec options[] = {
 
396
    {"-background", ".background", XrmoptionSepArg, 0},
 
397
    {"-foreground", ".foreground", XrmoptionSepArg, 0},
 
398
    {"-draw-delay", ".drawDelay", XrmoptionSepArg, 0},
 
399
    {"-num-discs", ".numDiscs", XrmoptionSepArg, 0},
 
400
    {"-max-riders", ".maxRiders", XrmoptionSepArg, 0},
 
401
    {"-max-radius", ".maxRadius", XrmoptionSepArg, 0},
 
402
    {0, 0, 0, 0}
 
403
};
 
404
 
 
405
void build_img(Display *dpy, Window window, struct field *f) {
 
406
    if (f->off_alpha) {
 
407
        free(f->off_alpha);
 
408
        f->off_alpha = NULL;
 
409
 
 
410
        /* Assume theres also an off pixmap */
 
411
        XFreePixmap(dpy, f->off_map);
 
412
    }
 
413
 
 
414
    f->off_alpha = (unsigned long *) xrealloc(f->off_alpha, sizeof(unsigned long) * 
 
415
                                              f->width * f->height);
 
416
 
 
417
    memset(f->off_alpha, f->bgcolor, sizeof(unsigned long) * f->width * f->height);
 
418
 
 
419
    f->off_map = XCreatePixmap(dpy, window, f->width, f->height, f->visdepth);
 
420
 
 
421
}
 
422
 
 
423
inline void blank_img(Display *dpy, Window window, XWindowAttributes xgwa, GC fgc, struct field *f) {
 
424
    memset(f->off_alpha, f->bgcolor, sizeof(unsigned long) * f->width * f->height);
 
425
 
 
426
    XSetForeground(dpy, fgc, f->bgcolor);
 
427
    XFillRectangle(dpy, window, fgc, 0, 0, xgwa.width, xgwa.height);
 
428
    XSetForeground(dpy, fgc, f->fgcolor);
 
429
}
 
430
 
 
431
void screenhack(Display * dpy, Window window)
 
432
{
 
433
    struct field *f = init_field();
 
434
 
 
435
#ifdef TIME_ME
 
436
    time_t start_time = time(NULL);
 
437
#endif
 
438
 
 
439
    int draw_delay = 0;
 
440
    int tempx;
 
441
 
 
442
    GC fgc, copygc;
 
443
    XGCValues gcv;
 
444
    XWindowAttributes xgwa;
 
445
 
 
446
    draw_delay = (get_integer_resource("drawDelay", "Integer"));
 
447
    f->maxrider = (get_integer_resource("maxRiders", "Integer"));
 
448
    f->maxradius = (get_integer_resource("maxRadius", "Integer"));
 
449
    f->initial_discs = (get_integer_resource("numDiscs", "Integer"));
 
450
 
 
451
    if (f->initial_discs <= 10) {
 
452
        fprintf(stderr, "%s: Initial discs must be greater than 10\n", progname);
 
453
        return;
 
454
    }
 
455
 
 
456
    if (f->maxradius <= 30) {
 
457
        fprintf(stderr, "%s: Max radius must be greater than 30\n", progname);
 
458
        return;
 
459
    }
 
460
 
 
461
    if (f->maxrider <= 10) {
 
462
        fprintf(stderr, "%s: Max riders must be greater than 10\n", progname);
 
463
        return;
 
464
    }
 
465
    
 
466
    XGetWindowAttributes(dpy, window, &xgwa);
 
467
 
 
468
    f->height = xgwa.height;
 
469
    f->width = xgwa.width;
 
470
    f->visdepth = xgwa.depth;
 
471
 
 
472
    gcv.foreground = get_pixel_resource("foreground", "Foreground",
 
473
                                        dpy, xgwa.colormap);
 
474
    gcv.background = get_pixel_resource("background", "Background",
 
475
                                        dpy, xgwa.colormap);
 
476
    fgc = XCreateGC(dpy, window, GCForeground, &gcv);
 
477
    copygc = XCreateGC(dpy, window, GCForeground, &gcv);
 
478
 
 
479
    f->fgcolor = gcv.foreground;
 
480
    f->bgcolor = gcv.background;
 
481
 
 
482
    /* Initialize stuff */
 
483
    build_img(dpy, window, f);
 
484
 
 
485
    for (tempx = 0; tempx < f->initial_discs; tempx++) {
 
486
        float fx, fy, x, y, r;
 
487
        int bt;
 
488
 
 
489
        /* Arrange in anti-collapsing circle */
 
490
        fx = 0.4 * f->width * cos((2 * M_PI) * tempx / f->initial_discs);
 
491
        fy = 0.4 * f->height * sin((2 * M_PI) * tempx / f->initial_discs);
 
492
        x = frand(f->width / 2) + fx;
 
493
        y = frand(f->height / 2) + fy;
 
494
        r = 5 + frand(f->maxradius);
 
495
        bt = 1;
 
496
 
 
497
        if ((random() % 100) < 50)
 
498
            bt = -1;
 
499
 
 
500
        make_disc(f, x, y, bt * fx / 1000.0, bt * fy / 1000.0, r);
 
501
        
 
502
    }
 
503
    
 
504
    while (1) {
 
505
        if ((f->cycles % 10) == 0) {
 
506
            /* Restart if the window size changes */
 
507
            XGetWindowAttributes(dpy, window, &xgwa);
 
508
 
 
509
            if (f->height != xgwa.height || f->width != xgwa.width) {
 
510
                f->height = xgwa.height;
 
511
                f->width = xgwa.width;
 
512
                f->visdepth = xgwa.depth;
 
513
 
 
514
                build_img(dpy, window, f);
 
515
            }
 
516
        }
 
517
 
 
518
        blank_img(dpy, f->off_map, xgwa, fgc, f);
 
519
        for (tempx = 0; tempx < f->num; tempx++) {
 
520
            move_disc(f, tempx);
 
521
            render_disc(dpy, f->off_map, fgc, f, tempx);
 
522
        }
 
523
 
 
524
        XSetFillStyle(dpy, copygc, FillTiled);
 
525
        XSetTile(dpy, copygc, f->off_map);
 
526
        XFillRectangle(dpy, window, copygc, 0, 0, f->width, f->height);
 
527
 
 
528
        f->cycles++;
 
529
 
 
530
/*        XSync(dpy, False); */
 
531
 
 
532
        screenhack_handle_events(dpy);
 
533
 
 
534
        if (draw_delay)
 
535
            usleep(draw_delay);
 
536
    }
 
537
}