-/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
+ * 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
*/
#include "screenhack.h"
+#include "alpha.h"
#include <stdio.h>
+#define MAXPOLY 16
+#define SCALE 6
+
struct qpoint {
int x, y;
int dx, dy;
};
struct qline {
- struct qpoint p1, p2;
+ struct qpoint *p;
XColor color;
Bool dead;
};
int id;
int fp;
int nlines;
+ int npoly;
struct qline *lines;
};
static GC draw_gc, erase_gc;
static unsigned int default_fg_pixel;
-static int maxx, maxy, max_spread, max_size, color_shift;
-static Bool random_p, solid_p, xor_p, transparent_p;
+static long maxx, maxy, max_spread, max_size;
+static int color_shift;
+static Bool random_p, solid_p, xor_p, transparent_p, gravity_p;
static int delay;
static int count;
static Colormap cmap;
-static unsigned long base_pixel;
+static int npoly;
static GC *gcs[2];
static void
-get_geom (dpy, window)
- Display *dpy;
- Window window;
+get_geom (Display *dpy, Window window)
{
XWindowAttributes xgwa;
XGetWindowAttributes (dpy, window, &xgwa);
- maxx = xgwa.width;
- maxy = xgwa.height;
+ maxx = ((long)(xgwa.width+1)<<SCALE) - 1;
+ maxy = ((long)(xgwa.height+1)<<SCALE) - 1;
}
static struct qix *
-init_one_qix (dpy, window, nlines)
- Display *dpy;
- Window window;
- int nlines;
+init_one_qix (Display *dpy, Window window, int nlines, int npoly)
{
- int i;
+ int i, j;
struct qix *qix = (struct qix *) calloc (1, sizeof (struct qix));
qix->nlines = nlines;
qix->lines = (struct qline *) calloc (qix->nlines, sizeof (struct qline));
-
+ qix->npoly = npoly;
+ for (i = 0; i < qix->nlines; i++)
+ qix->lines[i].p = (struct qpoint *)
+ calloc(qix->npoly, sizeof(struct qpoint));
+
if (!mono_p && !transparent_p)
{
hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
{
qix->lines[0].color.pixel = default_fg_pixel;
- if (!XQueryColor (dpy, cmap, &qix->lines[0].color))
- abort ();
+ XQueryColor (dpy, cmap, &qix->lines[0].color);
if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
abort ();
}
}
- qix->lines[0].p1.x = random () % maxx;
- qix->lines[0].p1.y = random () % maxy;
+
if (max_size == 0)
{
- qix->lines[0].p2.x = random () % maxx;
- qix->lines[0].p2.y = random () % maxy;
+ for (i = 0; i < qix->npoly; i++)
+ {
+ qix->lines[0].p[i].x = random () % maxx;
+ qix->lines[0].p[i].y = random () % maxy;
+ }
}
else
{
- qix->lines[0].p2.x = qix->lines[0].p1.x + (random () % (max_size/2));
- qix->lines[0].p2.y = qix->lines[0].p1.y + (random () % (max_size/2));
- if (qix->lines[0].p2.x > maxx) qix->lines[0].p2.x = maxx;
- if (qix->lines[0].p2.y > maxy) qix->lines[0].p2.y = maxy;
+ /*assert(qix->npoly == 2);*/
+ qix->lines[0].p[0].x = random () % maxx;
+ qix->lines[0].p[0].y = random () % maxy;
+ qix->lines[0].p[1].x = qix->lines[0].p[0].x + (random () % (max_size/2));
+ qix->lines[0].p[1].y = qix->lines[0].p[0].y + (random () % (max_size/2));
+ if (qix->lines[0].p[1].x > maxx) qix->lines[0].p[1].x = maxx;
+ if (qix->lines[0].p[1].y > maxy) qix->lines[0].p[1].y = maxy;
+ }
+
+ for (i = 0; i < qix->npoly; i++)
+ {
+ qix->lines[0].p[i].dx = (random () % (max_spread + 1)) - (max_spread /2);
+ qix->lines[0].p[i].dy = (random () % (max_spread + 1)) - (max_spread /2);
}
- qix->lines[0].p1.dx = (random () % (max_spread + 1)) - (max_spread / 2);
- qix->lines[0].p1.dy = (random () % (max_spread + 1)) - (max_spread / 2);
- qix->lines[0].p2.dx = (random () % (max_spread + 1)) - (max_spread / 2);
- qix->lines[0].p2.dy = (random () % (max_spread + 1)) - (max_spread / 2);
qix->lines[0].dead = True;
+
for (i = 1; i < qix->nlines; i++)
{
- qix->lines[i] = qix->lines[0];
+ for(j=0; j<qix->npoly; j++)
+ qix->lines[i].p[j] = qix->lines[0].p[j];
+ qix->lines[i].color = qix->lines[0].color;
+ qix->lines[i].dead = qix->lines[0].dead;
+
if (!mono_p && !transparent_p)
if (!XAllocColor (dpy, cmap, &qix->lines[i].color))
abort ();
return qix;
}
-/* I don't believe this fucking language doesn't have builtin exponentiation.
- I further can't believe that the fucking ^ character means fucking XOR!! */
-static int i_exp(i,j)
- int i, j;
-{
- int k = 1;
- while (j--) k *= i;
- return k;
-}
-static void
-merge_colors (argc, argv, into_color, mask, increment_p)
- int argc;
- XColor **argv;
- XColor *into_color;
- int mask;
- Bool increment_p;
-{
- int j;
- *into_color = *argv [0];
- into_color->pixel |= mask;
-#define SHORT_INC(x,y) (x = ((((x)+(y)) > 0xFFFF) ? 0xFFFF : ((x)+(y))))
-#define SHORT_DEC(x,y) (x = ((((x)-(y)) < 0) ? 0 : ((x)-(y))))
- for (j = 1; j < argc; j++)
- if (increment_p)
- {
- SHORT_INC (into_color->red, argv[j]->red);
- SHORT_INC (into_color->green, argv[j]->green);
- SHORT_INC (into_color->blue, argv[j]->blue);
- }
- else
- {
- SHORT_DEC (into_color->red, argv[j]->red);
- SHORT_DEC (into_color->green, argv[j]->green);
- SHORT_DEC (into_color->blue, argv[j]->blue);
- }
-#undef SHORT_INC
-#undef SHORT_DEC
-}
-
-/* fill in all the permutations of colors that XAllocColorCells() has
- allocated for us. Thanks Ron, you're an additive kind of guy. */
-static void
-permute_colors (pcolors, colors, count, plane_masks, increment_p)
- XColor *pcolors, *colors;
- int count;
- unsigned long *plane_masks;
- Bool increment_p;
-{
- int out = 0;
- int max = i_exp (2, count);
- if (count > 31) abort ();
- for (out = 1; out < max; out++)
- {
- XColor *argv [32];
- int this_mask = 0;
- int argc = 0;
- int bit;
- for (bit = 0; bit < 32; bit++)
- if (out & (1<<bit))
- {
- argv [argc++] = &pcolors [bit];
- this_mask |= plane_masks [bit];
- }
- merge_colors (argc, argv, &colors [out-1], this_mask, increment_p);
- }
-}
-
static struct qix **
-init_qix (dpy, window)
- Display *dpy;
- Window window;
+init_qix (Display *dpy, Window window)
{
int nlines;
struct qix **qixes;
if (count <= 0) count = 1;
nlines = get_integer_resource ("segments", "Integer");
if (nlines <= 0) nlines = 20;
+ npoly = get_integer_resource("poly", "Integer");
+ if (npoly <= 2) npoly = 2;
+ if (npoly > MAXPOLY) npoly = MAXPOLY;
get_geom (dpy, window);
max_spread = get_integer_resource ("spread", "Integer");
if (max_spread <= 0) max_spread = 10;
+ max_spread <<= SCALE;
max_size = get_integer_resource ("size", "Integer");
if (max_size < 0) max_size = 0;
+ max_size <<= SCALE;
random_p = get_boolean_resource ("random", "Boolean");
solid_p = get_boolean_resource ("solid", "Boolean");
xor_p = get_boolean_resource ("xor", "Boolean");
transparent_p = get_boolean_resource ("transparent", "Boolean");
+ gravity_p = get_boolean_resource("gravity", "Boolean");
delay = get_integer_resource ("delay", "Integer");
color_shift = get_integer_resource ("colorShift", "Integer");
if (color_shift < 0 || color_shift >= 360) color_shift = 5;
if (delay < 0) delay = 0;
+ /* Clear up ambiguities regarding npoly */
+ if (solid_p)
+ {
+ if (npoly != 2)
+ fprintf(stderr, "%s: Can't have -solid and -poly; using -poly 2\n",
+ progname);
+ npoly = 2;
+ }
+ if (npoly > 2)
+ {
+ if (max_size)
+ fprintf(stderr, "%s: Can't have -poly and -size; using -size 0\n",
+ progname);
+ max_size = 0;
+ }
+
if (count == 1 && transparent_p)
transparent_p = False; /* it's a no-op */
if (transparent_p)
{
- Bool increment_p = get_boolean_resource ("additive", "Boolean");
- unsigned long plane_masks [32];
- XColor *pcolors, *colors;
+ Bool additive_p = get_boolean_resource ("additive", "Boolean");
+ unsigned long *plane_masks = 0;
+ unsigned long base_pixel;
int nplanes = count;
- int i, total_colors;
+ int i;
- /* permutations would be harder if the number of planes didn't fit
- in an int. Who has >32-bit displays anyway... */
- if (nplanes > 31) nplanes = 31;
-
- while (nplanes > 1 &&
- !XAllocColorCells (dpy, cmap, False, plane_masks, nplanes,
- &base_pixel, 1))
- nplanes--;
+ allocate_alpha_colors (dpy, cmap, &nplanes, additive_p, &plane_masks,
+ &base_pixel);
if (nplanes <= 1)
{
gcs[0] = (GC *) malloc (count * sizeof (GC));
gcs[1] = xor_p ? gcs[0] : (GC *) malloc (count * sizeof (GC));
- total_colors = i_exp (2, count);
- pcolors = (XColor *) calloc (count, sizeof (XColor));
- colors = (XColor *) calloc (total_colors, sizeof (XColor));
+
+
for (i = 0; i < count; i++)
{
gcv.plane_mask = plane_masks [i];
gcs [1][i] = XCreateGC (dpy, window, GCForeground|GCPlaneMask,
&gcv);
}
-
- /* pick the "primary" (not in that sense) colors.
- If we are in subtractive mode, pick higher intensities. */
- hsv_to_rgb (random () % 360, frand (1.0),
- frand (0.5) + (increment_p ? 0.2 : 0.5),
- &pcolors[i].red, &pcolors[i].green, &pcolors[i].blue);
-
- pcolors [i].flags = DoRed | DoGreen | DoBlue;
- pcolors [i].pixel = base_pixel | plane_masks [i];
}
- permute_colors (pcolors, colors, count, plane_masks, increment_p);
- /* clone the default background of the window into our "base" pixel */
- colors [total_colors - 1].pixel =
- get_pixel_resource ("background", "Background", dpy, cmap);
- XQueryColor (dpy, cmap, &colors [total_colors - 1]);
- colors [total_colors - 1].pixel = base_pixel;
- XStoreColors (dpy, cmap, colors, total_colors);
+
XSetWindowBackground (dpy, window, base_pixel);
XClearWindow (dpy, window);
}
qixes [count] = 0;
while (count--)
{
- qixes [count] = init_one_qix (dpy, window, nlines);
+ qixes [count] = init_one_qix (dpy, window, nlines, npoly);
qixes [count]->id = count;
}
return qixes;
}
static void
-free_qline (dpy, window, cmap, qline, prev, qix)
- Display *dpy;
- Window window;
- Colormap cmap;
- struct qline *qline, *prev;
- struct qix *qix;
+free_qline (Display *dpy, Window window, Colormap cmap,
+ struct qline *qline,
+ struct qline *prev,
+ struct qix *qix)
{
+ int i;
if (qline->dead || !prev)
;
else if (solid_p)
{
XPoint points [4];
- points [0].x = qline->p1.x; points [0].y = qline->p1.y;
- points [1].x = qline->p2.x; points [1].y = qline->p2.y;
- points [2].x = prev->p2.x; points [2].y = prev->p2.y;
- points [3].x = prev->p1.x; points [3].y = prev->p1.y;
+ /*assert(qix->npoly == 2);*/
+ points [0].x = qline->p[0].x >> SCALE;
+ points [0].y = qline->p[0].y >> SCALE;
+ points [1].x = qline->p[1].x >> SCALE;
+ points [1].y = qline->p[1].y >> SCALE;
+ points [2].x = prev->p[1].x >> SCALE;
+ points [2].y = prev->p[1].y >> SCALE;
+ points [3].x = prev->p[0].x >> SCALE;
+ points [3].y = prev->p[0].y >> SCALE;
XFillPolygon (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
points, 4, Complex, CoordModeOrigin);
}
else
- XDrawLine (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
- qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);
+ {
+ /* XDrawLine (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
+ qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);*/
+ static XPoint points[MAXPOLY+1];
+ for(i = 0; i < qix->npoly; i++)
+ {
+ points[i].x = qline->p[i].x >> SCALE;
+ points[i].y = qline->p[i].y >> SCALE;
+ }
+ points[qix->npoly] = points[0];
+ XDrawLines(dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
+ points, qix->npoly+1, CoordModeOrigin);
+ }
if (!mono_p && !transparent_p)
XFreeColors (dpy, cmap, &qline->color.pixel, 1, 0);
}
static void
-add_qline (dpy, window, cmap, qline, prev_qline, qix)
- Display *dpy;
- Window window;
- Colormap cmap;
- struct qline *qline, *prev_qline;
- struct qix *qix;
+add_qline (Display *dpy, Window window, Colormap cmap,
+ struct qline *qline,
+ struct qline *prev_qline,
+ struct qix *qix)
{
- *qline = *prev_qline;
+ int i;
+
+ for(i=0; i<qix->npoly; i++)
+ qline->p[i] = prev_qline->p[i];
+ qline->color = prev_qline->color;
+ qline->dead = prev_qline->dead;
#define wiggle(point,delta,max) \
- if (random_p) delta += (random () % 3) - 1; \
+ if (random_p) delta += (random () % (1 << (SCALE+1))) - (1 << SCALE); \
if (delta > max_spread) delta = max_spread; \
else if (delta < -max_spread) delta = -max_spread; \
point += delta; \
if (point < 0) point = 0, delta = -delta, point += delta<<1; \
else if (point > max) point = max, delta = -delta, point += delta<<1;
-
- wiggle (qline->p1.x, qline->p1.dx, maxx);
- wiggle (qline->p1.y, qline->p1.dy, maxy);
- wiggle (qline->p2.x, qline->p2.dx, maxx);
- wiggle (qline->p2.y, qline->p2.dy, maxy);
+
+ if (gravity_p)
+ for(i=0; i<qix->npoly; i++)
+ qline->p[i].dy += 3;
+
+ for (i = 0; i < qix->npoly; i++)
+ {
+ wiggle (qline->p[i].x, qline->p[i].dx, maxx);
+ wiggle (qline->p[i].y, qline->p[i].dy, maxy);
+ }
if (max_size)
{
- if (qline->p1.x - qline->p2.x > max_size)
- qline->p1.x = qline->p2.x + max_size
+ /*assert(qix->npoly == 2);*/
+ if (qline->p[0].x - qline->p[1].x > max_size)
+ qline->p[0].x = qline->p[1].x + max_size
- (random_p ? random() % max_spread : 0);
- else if (qline->p2.x - qline->p1.x > max_size)
- qline->p2.x = qline->p1.x + max_size
+ else if (qline->p[1].x - qline->p[0].x > max_size)
+ qline->p[1].x = qline->p[0].x + max_size
- (random_p ? random() % max_spread : 0);
- if (qline->p1.y - qline->p2.y > max_size)
- qline->p1.y = qline->p2.y + max_size
+ if (qline->p[0].y - qline->p[1].y > max_size)
+ qline->p[0].y = qline->p[1].y + max_size
- (random_p ? random() % max_spread : 0);
- else if (qline->p2.y - qline->p1.y > max_size)
- qline->p2.y = qline->p1.y + max_size
+ else if (qline->p[1].y - qline->p[0].y > max_size)
+ qline->p[1].y = qline->p[0].y + max_size
- (random_p ? random() % max_spread : 0);
}
if (!mono_p && !transparent_p)
{
- cycle_hue (&qline->color, color_shift);
+ XColor desired;
+
+ int h;
+ double s, v;
+ rgb_to_hsv (qline->color.red, qline->color.green, qline->color.blue,
+ &h, &s, &v);
+ h = (h + color_shift) % 360;
+ hsv_to_rgb (h, s, v,
+ &qline->color.red, &qline->color.green, &qline->color.blue);
+
qline->color.flags = DoRed | DoGreen | DoBlue;
- if (!XAllocColor (dpy, cmap, &qline->color))
+ desired = qline->color;
+ if (XAllocColor (dpy, cmap, &qline->color))
+ {
+ /* XAllocColor returns the actual RGB that the hardware let us
+ allocate. Restore the requested values into the XColor struct
+ so that limited-resolution hardware doesn't cause the cycle to
+ get "stuck". */
+ qline->color.red = desired.red;
+ qline->color.green = desired.green;
+ qline->color.blue = desired.blue;
+ }
+ else
{
qline->color = prev_qline->color;
if (!XAllocColor (dpy, cmap, &qline->color))
XSetForeground (dpy, draw_gc, qline->color.pixel);
}
if (! solid_p)
- XDrawLine (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
- qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);
+ {
+ /* XDrawLine (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
+ qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);*/
+ static XPoint points[MAXPOLY+1];
+ for (i = 0; i < qix->npoly; i++)
+ {
+ points[i].x = qline->p[i].x >> SCALE;
+ points[i].y = qline->p[i].y >> SCALE;
+ }
+ points[qix->npoly] = points[0];
+ XDrawLines(dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
+ points, qix->npoly+1, CoordModeOrigin);
+ }
else if (!prev_qline->dead)
{
XPoint points [4];
- points [0].x = qline->p1.x; points [0].y = qline->p1.y;
- points [1].x = qline->p2.x; points [1].y = qline->p2.y;
- points [2].x = prev_qline->p2.x; points [2].y = prev_qline->p2.y;
- points [3].x = prev_qline->p1.x; points [3].y = prev_qline->p1.y;
+ points [0].x = qline->p[0].x >> SCALE;
+ points [0].y = qline->p[0].y >> SCALE;
+ points [1].x = qline->p[1].x >> SCALE;
+ points [1].y = qline->p[1].y >> SCALE;
+ points [2].x = prev_qline->p[1].x >> SCALE;
+ points [2].y = prev_qline->p[1].y >> SCALE;
+ points [3].x = prev_qline->p[0].x >> SCALE;
+ points [3].y = prev_qline->p[0].y >> SCALE;
XFillPolygon (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
points, 4, Complex, CoordModeOrigin);
}
}
static void
-qix1 (dpy, window, qix)
- Display *dpy;
- Window window;
- struct qix *qix;
+qix1 (Display *dpy, Window window, struct qix *qix)
{
int ofp = qix->fp - 1;
static int gtick = 0;
+ if (ofp < 0) ofp = qix->nlines - 1;
if (gtick++ == 500)
get_geom (dpy, window), gtick = 0;
- if (ofp < 0) ofp = qix->nlines - 1;
free_qline (dpy, window, cmap, &qix->lines [qix->fp],
&qix->lines[(qix->fp + 1) % qix->nlines], qix);
add_qline (dpy, window, cmap, &qix->lines[qix->fp], &qix->lines[ofp], qix);
char *progclass = "Qix";
char *defaults [] = {
- "*background: black",
- "*foreground: white",
+ ".background: black",
+ ".foreground: white",
"*count: 1",
"*segments: 50",
+ "*poly: 2",
"*spread: 8",
"*size: 0",
"*colorShift: 3",
"*random: true",
"*xor: false",
"*transparent:false",
+ "*gravity: false",
"*additive: true",
0
};
XrmOptionDescRec options [] = {
{ "-count", ".count", XrmoptionSepArg, 0 },
{ "-segments", ".segments", XrmoptionSepArg, 0 },
+ { "-poly", ".poly", XrmoptionSepArg, 0 },
{ "-spread", ".spread", XrmoptionSepArg, 0 },
{ "-size", ".size", XrmoptionSepArg, 0 },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-no-xor", ".xor", XrmoptionNoArg, "false" },
{ "-transparent", ".transparent", XrmoptionNoArg, "true" },
{ "-non-transparent", ".transparent", XrmoptionNoArg, "false" },
+ { "-gravity", ".gravity", XrmoptionNoArg, "true" },
+ { "-no-gravity", ".gravity", XrmoptionNoArg, "false" },
{ "-additive", ".additive", XrmoptionNoArg, "true" },
{ "-subtractive", ".additive", XrmoptionNoArg, "false" },
+ { 0, 0, 0, 0 }
};
-int options_size = (sizeof (options) / sizeof (options[0]));
void
-screenhack (dpy, window)
- Display *dpy;
- Window window;
+screenhack (Display *dpy, Window window)
{
struct qix **q1 = init_qix (dpy, window);
struct qix **qn;
for (qn = q1; *qn; qn++)
{
qix1 (dpy, window, *qn);
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}