diff options
Diffstat (limited to 'hacks/intermomentary.c')
-rw-r--r-- | hacks/intermomentary.c | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/hacks/intermomentary.c b/hacks/intermomentary.c new file mode 100644 index 0000000..4e65b76 --- /dev/null +++ b/hacks/intermomentary.c @@ -0,0 +1,577 @@ +/* + * InterMomentary (dragorn@kismetwireless.net) + * Directly ported code from complexification.net InterMomentary art + * http://www.complexification.net/gallery/machines/interMomentary/applet_l/interMomentary_l.pde + * + * Intersecting Circles, Instantaneous + * J. Tarbell + complexification.net + * Albuquerque, New Mexico + * May, 2004 + * + * a REAS collaboration for the + groupc.net + * Whitney Museum of American Art ARTPORT + artport.whitney.org + * Robert Hodgin + flight404.com + * William Ngan + metaphorical.net + * + * + * 1.0 Oct 10 2004 dragorn Completed first port + * + * + * Based, of course, on other hacks in: + * + * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include <math.h> +#include "screenhack.h" +#include "hsv.h" + +/* this program goes faster if some functions are inline. The following is + * borrowed from ifs.c */ +#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) +#undef inline +#define inline /* */ +#endif + +/* Pixel rider */ +typedef struct { + float t; + float vt; + float mycharge; +} PxRider; + +/* disc of light */ +typedef struct { + /* index identifier */ + int id; + /* position */ + float x, y; + /* radius */ + float r, dr; + /* velocity */ + float vx, vy; + + /* pixel riders */ + int numr; + PxRider *pxRiders; +} Disc; + +struct field { + unsigned int height; + unsigned int width; + + int initial_discs; + Disc *discs; + + unsigned int num; + + unsigned int maxrider; + unsigned int maxradius; + + /* color parms */ + unsigned long fgcolor; + unsigned long bgcolor; + int visdepth; + + unsigned int cycles; + + /* Offscreen image we draw to */ + Pixmap off_map; + unsigned char *off_alpha; +}; + + +struct state { + Display *dpy; + Window window; + + struct field *f; + GC fgc, copygc; + XWindowAttributes xgwa; + int draw_delay; + + XColor *colors; + int ncolors; +}; + + +static void *xrealloc(void *p, size_t size) +{ + void *ret; + if ((ret = realloc(p, size)) == NULL) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + return ret; +} + +static struct field *init_field(void) +{ + struct field *f = xrealloc(NULL, sizeof(struct field)); + f->height = 0; + f->width = 0; + f->initial_discs = 0; + f->discs = NULL; + f->num = 0; + f->maxrider = 0; + f->maxradius = 0; + f->cycles = 0; + f->fgcolor = 0; + f->bgcolor = 0; + f->off_alpha = NULL; + f->visdepth = 0; + return f; +} + +/* Quick-ref to pixels in the alpha map */ +#define ref_pixel(f, x, y) ((f)->off_alpha[(y) * (f)->width + (x)]) + +static inline void make_disc(struct field *f, float x, float y, float vx, float vy, float r) +{ + /* Synthesis of Disc::Disc and PxRider::PxRider */ + Disc *nd; + int ix; + + /* allocate a new disc */ + f->discs = (Disc *) xrealloc(f->discs, sizeof(Disc) * (f->num + 1)); + + nd = &(f->discs[f->num]); + + nd->id = f->num++; + nd->x = x; + nd->y = y; + nd->vx = vx; + nd->vy = vy; + nd->dr = r; + nd->r = frand(r) / 3; + + nd->numr = (frand(r) / 2.62); + if (nd->numr > f->maxrider) + nd->numr = f->maxrider; + + nd->pxRiders = NULL; + nd->pxRiders = (PxRider *) xrealloc(nd->pxRiders, sizeof(PxRider) * (f->maxrider)); + for (ix = 0; ix < f->maxrider; ix++) { + nd->pxRiders[ix].vt = 0.0; + nd->pxRiders[ix].t = frand(M_PI * 2); + nd->pxRiders[ix].mycharge = 0; + } +} + + +/* alpha blended point drawing */ +static inline unsigned long +trans_point(struct state *st, + int x1, int y1, unsigned char myc, float a, struct field *f) +{ + if ((x1 >= 0) && (x1 < f->width) && (y1 >= 0) && (y1 < f->height)) { + if (a >= 1.0) { + ref_pixel(f, x1, y1) = myc; + } else { + unsigned long c = ref_pixel(f, x1, y1); + c = c + (myc - c) * a; + ref_pixel(f, x1, y1) = c; + return c; + } + } + + return 0; +} + +static inline unsigned long +get_pixel (struct state *st, unsigned char v) +{ + return st->colors [v * (st->ncolors-1) / 255].pixel; +} + + +static inline void move_disc(struct field *f, int dnum) +{ + Disc *d = &(f->discs[dnum]); + + /* add velocity to position */ + d->x += d->vx; + d->y += d->vy; + + /* bound check */ + if (d->x + d->r < 0) + d->x += f->width + d->r + d->r; + if (d->x - d->r > f->width) + d->x -= f->width + d->r + d->r; + if (d->y + d->r < 0) + d->y += f->height + d->r + d->r; + if (d->y - d->r > f->height) + d->y -= f->height + d->r + d->r; + + /* increase to destination radius */ + if (d->r < d->dr) + d->r += 0.1; +} + +static inline void +draw_glowpoint(struct state *st, Drawable drawable, + GC fgc, struct field *f, float px, float py) +{ + int i, j; + float a; + unsigned long c; + + for (i = -2; i < 3; i++) { + for (j = -2; j < 3; j++) { + a = 0.8 - i * i * 0.1 - j * j * 0.1; + + c = trans_point(st, px+i, py+j, 255, a, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, px + i, py + j); + XSetForeground(st->dpy, fgc, f->fgcolor); + } + } +} + +static inline void +moverender_rider(struct state *st, Drawable drawable, + GC fgc, struct field *f, PxRider *rid, + float x, float y, float r) +{ + float px, py; + unsigned long int c; + double cv; + + /* add velocity to theta */ + rid->t = fmod((rid->t + rid->vt + M_PI), (2 * M_PI)) - M_PI; + + rid->vt += frand(0.002) - 0.001; + + /* apply friction brakes */ + if (fabsf(rid->vt) > 0.02) + rid->vt *= 0.9; + + /* draw */ + px = x + r * cos(rid->t); + py = y + r * sin(rid->t); + + if ((px < 0) || (px >= f->width) || (py < 0) || (py >= f->height)) + return; + + /* max brightness seems to be 0.003845 */ + + c = ref_pixel(f, (int) px, (int) py); + cv = c / 255.0; + + /* guestimated - 40 is 18% of 255, so scale this to 0.0 to 0.003845 */ + if (cv > 0.0006921) { + draw_glowpoint(st, drawable, fgc, f, px, py); + + rid->mycharge = 0.003845; + } else { + rid->mycharge *= 0.98; + + c = 255 * rid->mycharge; + + trans_point(st, px, py, c, 0.5, f); + + XSetForeground(st->dpy, fgc, get_pixel(st, c)); + XDrawPoint(st->dpy, drawable, fgc, px, py); + XSetForeground(st->dpy, fgc, f->fgcolor); + } +} + +static inline void +render_disc(struct state *st, Drawable drawable, GC fgc, struct field *f, int dnum) +{ + Disc *di = &(f->discs[dnum]); + int n, m; + float dx, dy, d; + float a, p2x, p2y, h, p3ax, p3ay, p3bx, p3by; + unsigned long c; + + /* Find intersecting points with all ascending discs */ + for (n = di->id + 1; n < f->num; n++) { + dx = f->discs[n].x - di->x; + dy = f->discs[n].y - di->y; + d = sqrt(dx * dx + dy * dy); + + /* intersection test */ + if (d < (f->discs[n].r + di->r)) { + /* complete containment test */ + if (d > fabsf(f->discs[n].r - di->r)) { + /* find solutions */ + a = (di->r * di->r - f->discs[n].r * f->discs[n].r + d * d) / (2 * d); + p2x = di->x + a * (f->discs[n].x - di->x) / d; + p2y = di->y + a * (f->discs[n].y - di->y) / d; + + h = sqrt(di->r * di->r - a * a); + + p3ax = p2x + h * (f->discs[n].y - di->y) / d; + p3ay = p2y - h * (f->discs[n].x - di->x) / d; + + p3bx = p2x - h * (f->discs[n].y - di->y) / d; + p3by = p2y + h * (f->discs[n].x - di->x) / d; + + /* bounds check */ + if ((p3ax < 0) || (p3ax >= f->width) || (p3ay < 0) || (p3ay >= f->height) || + (p3bx < 0) || (p3bx >= f->width) || (p3by < 0) || (p3by >= f->height)) + continue; + + /* p3a and p3b might be identical, ignore this case for now */ + /* XPutPixel(f->off_map, p3ax, p3ay, f->fgcolor); */ + c = trans_point(st, p3ax, p3ay, 255, 0.75, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, p3ax, p3ay); + + /* XPutPixel(f->off_map, p3bx, p3by, f->fgcolor); */ + c = trans_point(st, p3bx, p3by, 255, 0.75, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, p3bx, p3by); + XSetForeground(st->dpy, fgc, f->fgcolor); + } + } + + } + + /* Render all the pixel riders */ + for (m = 0; m < di->numr; m++) { + moverender_rider(st, drawable, fgc, f, &(di->pxRiders[m]), + di->x, di->y, di->r); + } +} + +static void build_img(Display *dpy, Window window, struct field *f) +{ + if (f->off_alpha) { + free(f->off_alpha); + f->off_alpha = NULL; + + /* Assume theres also an off pixmap */ + if (f->off_map != window) + XFreePixmap(dpy, f->off_map); + } + + f->off_alpha = (unsigned char *) + xrealloc(f->off_alpha, sizeof(unsigned char) * f->width * f->height); + + memset(f->off_alpha, 0, sizeof(unsigned char) * f->width * f->height); + +# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + /* Or Android's */ + f->off_map = window; +# else + f->off_map = XCreatePixmap(dpy, window, f->width, f->height, f->visdepth); +# endif + +} + +static inline void blank_img(Display *dpy, Window window, XWindowAttributes xgwa, GC fgc, struct field *f) +{ + memset(f->off_alpha, 0, sizeof(unsigned char) * f->width * f->height); + + XSetForeground(dpy, fgc, f->bgcolor); + XFillRectangle(dpy, window, fgc, 0, 0, xgwa.width, xgwa.height); + XSetForeground(dpy, fgc, f->fgcolor); +} + + +static void * +intermomentary_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + +#ifdef TIME_ME + time_t start_time = time(NULL); +#endif + + int tempx; + XGCValues gcv; + + st->dpy = dpy; + st->window = window; + + XGetWindowAttributes(dpy, window, &st->xgwa); + + st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors++; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap, + "foreground", "Foreground"); + gcv.background = get_pixel_resource(dpy, st->xgwa.colormap, + "background", "Background"); + + { + XColor fgc, bgc; + int fgh, bgh; + double fgs, fgv, bgs, bgv; + fgc.pixel = gcv.foreground; + bgc.pixel = gcv.background; + XQueryColor (st->dpy, st->xgwa.colormap, &fgc); + XQueryColor (st->dpy, st->xgwa.colormap, &bgc); + rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv); + rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv); +#if 0 + bgh = fgh; + bgs = fgs; + bgv = fgv / 10.0; +#endif + make_color_ramp (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + bgh, bgs, bgv, + fgh, fgs, fgv, + st->colors, &st->ncolors, + False, /* closed */ + True, False); + } + + st->f = init_field(); + + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + st->draw_delay = (get_integer_resource(dpy, "drawDelay", "Integer")); + st->f->maxrider = (get_integer_resource(dpy, "maxRiders", "Integer")); + st->f->maxradius = (get_integer_resource(dpy, "maxRadius", "Integer")); + st->f->initial_discs = (get_integer_resource(dpy, "numDiscs", "Integer")); + + if (st->f->initial_discs <= 10) { + fprintf(stderr, "%s: Initial discs must be greater than 10\n", progname); + exit (1); + } + + if (st->f->maxradius <= 30) { + fprintf(stderr, "%s: Max radius must be greater than 30\n", progname); + exit (1); + } + + if (st->f->maxrider <= 10) { + fprintf(stderr, "%s: Max riders must be greater than 10\n", progname); + exit (1); + } + + st->fgc = XCreateGC(dpy, window, GCForeground, &gcv); + st->copygc = XCreateGC(dpy, window, GCForeground, &gcv); + + st->f->fgcolor = gcv.foreground; + st->f->bgcolor = gcv.background; + + /* Initialize stuff */ + build_img(dpy, window, st->f); + + for (tempx = 0; tempx < st->f->initial_discs; tempx++) { + float fx, fy, x, y, r; + int bt; + + /* Arrange in anti-collapsing circle */ + fx = 0.4 * st->f->width * cos((2 * M_PI) * tempx / st->f->initial_discs); + fy = 0.4 * st->f->height * sin((2 * M_PI) * tempx / st->f->initial_discs); + x = frand(st->f->width / 2) + fx; + y = frand(st->f->height / 2) + fy; + r = 5 + frand(st->f->maxradius); + bt = 1; + + if ((random() % 100) < 50) + bt = -1; + + make_disc(st->f, x, y, bt * fx / 1000.0, bt * fy / 1000.0, r); + + } + + return st; +} + +static unsigned long +intermomentary_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int tempx; + + if ((st->f->cycles % 10) == 0) { + /* Restart if the window size changes */ + XGetWindowAttributes(dpy, window, &st->xgwa); + + if (st->f->height != st->xgwa.height || st->f->width != st->xgwa.width) { + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + build_img(dpy, window, st->f); + } + } + + blank_img(dpy, st->f->off_map, st->xgwa, st->fgc, st->f); + for (tempx = 0; tempx < st->f->num; tempx++) { + move_disc(st->f, tempx); + render_disc(st, st->f->off_map, st->fgc, st->f, tempx); + } + +#if 0 + XSetFillStyle(dpy, st->copygc, FillTiled); + XSetTile(dpy, st->copygc, st->f->off_map); + XFillRectangle(dpy, window, st->copygc, 0, 0, st->f->width, st->f->height); +#else + if (st->f->off_map != window) + XCopyArea (dpy, st->f->off_map, window, st->copygc, 0, 0, + st->f->width, st->f->height, 0, 0); + +#endif + + st->f->cycles++; + + return st->draw_delay; +} + + +static void +intermomentary_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +intermomentary_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +intermomentary_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *intermomentary_defaults[] = { + ".lowrez: true", + ".background: black", + ".foreground: yellow", + "*drawDelay: 30000", + "*numDiscs: 85", + "*maxRiders: 40", + "*maxRadius: 100", + "*colors: 256", +# ifdef HAVE_MOBILE + "*ignoreRotation: True", +# endif + 0 +}; + +static XrmOptionDescRec intermomentary_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-draw-delay", ".drawDelay", XrmoptionSepArg, 0}, + {"-num-discs", ".numDiscs", XrmoptionSepArg, 0}, + {"-max-riders", ".maxRiders", XrmoptionSepArg, 0}, + {"-max-radius", ".maxRadius", XrmoptionSepArg, 0}, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("Intermomentary", intermomentary) |