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
6
* Intersecting Circles, Instantaneous
7
* J. Tarbell + complexification.net
8
* Albuquerque, New Mexico
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
17
* 1.0 Oct 10 2004 dragorn Completed first port
20
* Based, of course, on other hacks in:
22
* xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
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
33
#include "screenhack.h"
34
#include <X11/Xutil.h>
40
#define MAX_WIDTH SHRT_MAX
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)
67
/* index identifier */
90
unsigned int maxrider;
91
unsigned int maxradius;
94
unsigned long fgcolor;
95
unsigned long bgcolor;
100
/* Offscreen image we draw to */
102
unsigned long int *off_alpha;
105
static void *xrealloc(void *p, size_t size) {
107
if ((ret = realloc(p, size)) == NULL) {
108
fprintf(stderr, "%s: out of memory\n", progname);
114
struct field *init_field(void) {
115
struct field *f = xrealloc(NULL, sizeof(struct field));
118
f->initial_discs = 0;
131
/* Quick-ref to pixels in the alpha map */
132
#define ref_pixel(f, x, y) ((f)->off_alpha[(y) * (f)->width + (x)])
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 */
139
/* allocate a new disc */
140
f->discs = (Disc *) xrealloc(f->discs, sizeof(Disc) * (f->num + 1));
142
nd = &(f->discs[f->num]);
150
nd->r = frand(r) / 3;
152
nd->numr = (frand(r) / 2.62);
153
if (nd->numr > f->maxrider)
154
nd->numr = f->maxrider;
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;
165
inline void point2rgb(int depth, unsigned long c, unsigned short int *r,
166
unsigned short int *g, unsigned short int *b) {
170
*g = (c & 0xff00) >> 8;
171
*r = (c & 0xff0000) >> 16;
175
*g = ((c >> 5) & 0x3f) << 2;
176
*r = ((c >> 11) & 0x1f) << 3;
177
*b = (c & 0x1f) << 3;
180
*g = ((c >> 5) & 0x1f) << 3;
181
*r = ((c >> 10) & 0x1f) << 3;
182
*b = (c & 0x1f) << 3;
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;
195
ret |= (r << 16) | (g << 8) | b;
198
ret = ((r>>3) << 11) | ((g>>2)<<5) | (b>>3);
201
ret = ((r>>3) << 10) | ((g>>3)<<5) | (b>>3);
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)) {
212
ref_pixel(f, x1, y1) = myc;
214
unsigned short int or, og, ob;
215
unsigned short int r, g, b;
216
unsigned short int nr, ng, nb;
219
c = ref_pixel(f, x1, y1);
220
point2rgb(f->visdepth, c, &or, &og, &ob);
221
point2rgb(f->visdepth, myc, &r, &g, &b);
223
nr = or + (r - or) * a;
224
ng = og + (g - og) * a;
225
nb = ob + (b - ob) * a;
227
c = rgb2point(f->visdepth, nr, ng, nb);
228
ref_pixel(f, x1, y1) = c;
237
inline void move_disc(struct field *f, int dnum) {
238
Disc *d = &(f->discs[dnum]);
240
/* add velocity to position */
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;
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;
254
/* increase to destination radius */
259
inline void draw_glowpoint(Display *dpy, Window window, GC fgc, struct field *f, float px, float py) {
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;
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);
276
inline void moverender_rider(Display *dpy, Window window, GC fgc, struct field *f, PxRider *rid,
277
float x, float y, float r) {
280
unsigned short int cr, cg, cb;
284
/* add velocity to theta */
285
rid->t = fmod((rid->t + rid->vt + M_PI), (2 * M_PI)) - M_PI;
287
rid->vt += frand(0.002) - 0.001;
289
/* apply friction brakes */
290
if (abs(rid->vt) > 0.02)
294
px = x + r * cos(rid->t);
295
py = y + r * sin(rid->t);
297
if ((px < 0) || (px >= f->width) || (py < 0) || (py >= f->height))
300
/* max brightness seems to be 0.003845 */
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);
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);
310
rid->mycharge = 0.003845;
312
rid->mycharge *= 0.98;
314
hsv_to_rgb(ch, cs, rid->mycharge, &cr, &cg, &cb);
315
c = rgb2point(f->visdepth, cr, cg, cb);
317
trans_point(px, py, c, 0.5, f);
319
XSetForeground(dpy, fgc, c);
320
XDrawPoint(dpy, window, fgc, px, py);
321
XSetForeground(dpy, fgc, f->fgcolor);
325
inline void render_disc(Display *dpy, Window window, GC fgc, struct field *f, int dnum) {
326
Disc *di = &(f->discs[dnum]);
329
float a, p2x, p2y, h, p3ax, p3ay, p3bx, p3by;
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);
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)) {
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;
347
h = sqrt(di->r * di->r - a * a);
349
p3ax = p2x + h * (f->discs[n].y - di->y) / d;
350
p3ay = p2y - h * (f->discs[n].x - di->x) / d;
352
p3bx = p2x - h * (f->discs[n].y - di->y) / d;
353
p3by = p2y + h * (f->discs[n].x - di->x) / d;
356
if ((p3ax < 0) || (p3ax >= f->width) || (p3ay < 0) || (p3ay >= f->height) ||
357
(p3bx < 0) || (p3bx >= f->width) || (p3by < 0) || (p3by >= f->height))
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);
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);
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);
383
char *progclass = "InterMomentary";
386
".background: black",
387
".foreground: white",
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},
405
void build_img(Display *dpy, Window window, struct field *f) {
410
/* Assume theres also an off pixmap */
411
XFreePixmap(dpy, f->off_map);
414
f->off_alpha = (unsigned long *) xrealloc(f->off_alpha, sizeof(unsigned long) *
415
f->width * f->height);
417
memset(f->off_alpha, f->bgcolor, sizeof(unsigned long) * f->width * f->height);
419
f->off_map = XCreatePixmap(dpy, window, f->width, f->height, f->visdepth);
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);
426
XSetForeground(dpy, fgc, f->bgcolor);
427
XFillRectangle(dpy, window, fgc, 0, 0, xgwa.width, xgwa.height);
428
XSetForeground(dpy, fgc, f->fgcolor);
431
void screenhack(Display * dpy, Window window)
433
struct field *f = init_field();
436
time_t start_time = time(NULL);
444
XWindowAttributes xgwa;
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"));
451
if (f->initial_discs <= 10) {
452
fprintf(stderr, "%s: Initial discs must be greater than 10\n", progname);
456
if (f->maxradius <= 30) {
457
fprintf(stderr, "%s: Max radius must be greater than 30\n", progname);
461
if (f->maxrider <= 10) {
462
fprintf(stderr, "%s: Max riders must be greater than 10\n", progname);
466
XGetWindowAttributes(dpy, window, &xgwa);
468
f->height = xgwa.height;
469
f->width = xgwa.width;
470
f->visdepth = xgwa.depth;
472
gcv.foreground = get_pixel_resource("foreground", "Foreground",
474
gcv.background = get_pixel_resource("background", "Background",
476
fgc = XCreateGC(dpy, window, GCForeground, &gcv);
477
copygc = XCreateGC(dpy, window, GCForeground, &gcv);
479
f->fgcolor = gcv.foreground;
480
f->bgcolor = gcv.background;
482
/* Initialize stuff */
483
build_img(dpy, window, f);
485
for (tempx = 0; tempx < f->initial_discs; tempx++) {
486
float fx, fy, x, y, r;
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);
497
if ((random() % 100) < 50)
500
make_disc(f, x, y, bt * fx / 1000.0, bt * fy / 1000.0, r);
505
if ((f->cycles % 10) == 0) {
506
/* Restart if the window size changes */
507
XGetWindowAttributes(dpy, window, &xgwa);
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;
514
build_img(dpy, window, f);
518
blank_img(dpy, f->off_map, xgwa, fgc, f);
519
for (tempx = 0; tempx < f->num; tempx++) {
521
render_disc(dpy, f->off_map, fgc, f, tempx);
524
XSetFillStyle(dpy, copygc, FillTiled);
525
XSetTile(dpy, copygc, f->off_map);
526
XFillRectangle(dpy, window, copygc, 0, 0, f->width, f->height);
530
/* XSync(dpy, False); */
532
screenhack_handle_events(dpy);