1 /* xscreensaver, Copyright (c) 1999-2018 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Draws a grid of hexagons or other shapes and drops them out.
16 #include "screenhack.h"
18 #define countof(x) (sizeof(x)/sizeof(*(x)))
19 #define ABS(x) ((x)<0?-(x):(x))
21 /* Avoid rounding errors by using a larger fixed-point grid.
22 Without this, we got little pointy errors at some corners. */
28 double th, radius, i, speed;
36 XWindowAttributes xgwa;
38 int ncells, cells_size, gw, gh;
56 make_cells (state *st)
58 int grid_size = get_integer_resource (st->dpy, "size", "Size");
60 int size, r, gw, gh, x, y, i;
63 if (grid_size < 5) grid_size = 5;
65 size = ((st->xgwa.width > st->xgwa.height
66 ? st->xgwa.width : st->xgwa.height)
68 gw = st->xgwa.width / size;
69 gh = st->xgwa.height / size;
74 th = M_PI / st->sides;
80 th = M_PI / st->sides;
86 th = M_PI / st->sides / 2;
91 th = M_PI / st->sides;
98 gw += 3; /* leave a few extra columns off screen just in case */
101 st->ncells = gw * gh;
103 if (st->initted_p && !st->cells) abort();
104 if (!st->initted_p && st->cells) abort();
106 cells2 = (cell *) calloc (st->ncells, sizeof(*cells2));
107 if (! cells2) abort();
111 for (y = 0; y < (st->gh < gh ? st->gh : gh); y++)
112 for (x = 0; x < (st->gw < gw ? st->gw : gw); x++)
113 cells2[y * gw + x] = st->cells [y * st->gw + x];
123 for (y = 0; y < gh; y++)
124 for (x = 0; x < gw; x++)
126 cell *c = &st->cells[i];
127 c->sides = st->sides;
128 c->radius = SCALE * r;
135 c->cx = SCALE * x * size;
143 c->cx = SCALE * x * size;
149 c->cx -= SCALE * size;
151 c->cy = SCALE * y * size;
155 c->cx = SCALE * x * size;
156 c->cy = SCALE * y * size * sqrt(3)/2;
158 c->cx -= SCALE * size * 0.5;
161 c->cx = SCALE * x * size * 2;
162 c->cy = SCALE * y * size * 2;
165 c->cx = SCALE * x * size * 0.5;
166 c->cy = SCALE * y * size * sqrt(3)/2;
167 if ((x & 1) ^ (y & 1))
170 c->cy -= SCALE * r * 0.5;
179 c->speed = st->speed * (st->uniform_p ? 1 : (0.1 + frand(0.9)));
180 c->i = st->lockstep_p ? 0 : random() % r;
181 c->colors[0] = (st->lockstep_p ? 0 : random() % st->ncolors);
186 c->radius += SCALE; /* Avoid single-pixel erase rounding errors */
188 if (c->i > c->radius) c->i = c->radius;
189 if (c->colors[0] >= st->ncolors) c->colors[0] = st->ncolors-1;
190 if (c->colors[1] >= st->ncolors) c->colors[1] = st->ncolors-1;
195 st->initted_p = True;
200 draw_cell (state *st, cell *c)
204 for (j = 0; j <= 1; j++)
206 int r = (j == 0 ? c->radius : c->i);
207 for (i = 0; i < c->sides; i++)
209 double th = i * M_PI * 2 / c->sides;
210 points[i].x = (c->cx + r * cos (th + c->th) + 0.5) / SCALE;
211 points[i].y = (c->cy + r * sin (th + c->th) + 0.5) / SCALE;
213 XSetForeground (st->dpy, st->gc, st->colors[c->colors[j]].pixel);
214 XFillPolygon (st->dpy, st->window, st->gc, points, c->sides,
215 Convex, CoordModeOrigin);
218 c->i -= SCALE * c->speed;
222 c->colors[1] = c->colors[0];
223 if (c != &st->cells[0])
224 c->colors[0] = st->cells[0].colors[0];
226 c->colors[0] = random() % st->ncolors;
232 hexadrop_init_1 (Display *dpy, Window window, state *st)
239 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
240 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
241 st->speed = get_float_resource (st->dpy, "speed", "Speed");
242 if (st->speed < 0) st->speed = 0;
244 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
246 if (st->ncolors < 2) st->ncolors = 2;
248 st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
250 if (st->ncolors < 10)
251 make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
252 st->colors, &st->ncolors, False, True, 0, True);
254 make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
255 st->colors, &st->ncolors, True, 0, True);
256 XSetWindowBackground (dpy, window, st->colors[0].pixel);
258 s1 = get_string_resource (st->dpy, "uniform", "Uniform");
259 s2 = get_string_resource (st->dpy, "lockstep", "Lockstep");
261 if ((!s1 || !*s1 || !strcasecmp(s1, "maybe")) &&
262 (!s2 || !*s2 || !strcasecmp(s2, "maybe")))
264 /* When being random, don't do both. */
265 st->uniform_p = random() & 1;
266 st->lockstep_p = st->uniform_p ? 0 : random() & 1;
270 if (!s1 || !*s1 || !strcasecmp(s1, "maybe"))
271 st->uniform_p = random() & 1;
273 st->uniform_p = get_boolean_resource (st->dpy, "uniform", "Uniform");
275 if (!s2 || !*s2 || !strcasecmp(s2, "maybe"))
276 st->lockstep_p = random() & 1;
278 st->lockstep_p = get_boolean_resource (st->dpy, "lockstep","Lockstep");
282 st->sides = get_integer_resource (st->dpy, "sides", "Sides");
283 if (! (st->sides == 0 || st->sides == 3 || st->sides == 4 ||
284 st->sides == 6 || st->sides == 8))
286 printf ("%s: invalid number of sides: %d\n", progname, st->sides);
292 static int defs[] = { 3, 3, 3,
296 st->sides = defs[random() % countof(defs)];
300 gcv.foreground = st->colors[0].pixel;
301 st->gc = XCreateGC (dpy, window, GCForeground, &gcv);
306 hexadrop_init (Display *dpy, Window window)
308 state *st = (state *) calloc (1, sizeof(*st));
309 hexadrop_init_1 (dpy, window, st);
316 hexadrop_draw (Display *dpy, Window window, void *closure)
318 state *st = (state *) closure;
321 for (i = 0; i < st->ncells; i++)
322 draw_cell (st, &st->cells[i]);
329 hexadrop_reshape (Display *dpy, Window window, void *closure,
330 unsigned int w, unsigned int h)
332 state *st = (state *) closure;
333 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
339 hexadrop_free (Display *dpy, Window window, void *closure)
341 state *st = (state *) closure;
344 free_colors (st->xgwa.screen, st->xgwa.colormap, st->colors, st->ncolors);
355 XFreeGC (st->dpy, st->gc);
362 hexadrop_event (Display *dpy, Window window, void *closure, XEvent *event)
364 state *st = (state *) closure;
366 if (screenhack_event_helper (dpy, window, event))
371 hexadrop_free (st->dpy, st->window, st);
374 for (i = 0; i < st->ncells; i++)
375 st->cells[i].initted_p = False;
376 hexadrop_init_1 (st->dpy, st->window, st);
384 static const char *hexadrop_defaults [] = {
385 ".background: black",
386 ".foreground: white",
396 "*ignoreRotation: True",
401 static XrmOptionDescRec hexadrop_options [] = {
402 { "-delay", ".delay", XrmoptionSepArg, 0 },
403 { "-sides", ".sides", XrmoptionSepArg, 0 },
404 { "-size", ".size", XrmoptionSepArg, 0 },
405 { "-speed", ".speed", XrmoptionSepArg, 0 },
406 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
407 { "-uniform-speed", ".uniform", XrmoptionNoArg, "True" },
408 { "-no-uniform-speed",".uniform", XrmoptionNoArg, "False" },
409 { "-lockstep", ".lockstep", XrmoptionNoArg, "True" },
410 { "-no-lockstep", ".lockstep", XrmoptionNoArg, "False" },
414 XSCREENSAVER_MODULE ("Hexadrop", hexadrop)