1 /* cynosure --- draw some rectangles
3 * 01-aug-96: written in Java by ozymandias G desiderata <ogd@organic.com>
4 * 25-dec-97: ported to C and XScreenSaver by Jamie Zawinski <jwz@jwz.org>
7 * http://www.organic.com/staff/ogd/java/cynosure.html
8 * http://www.organic.com/staff/ogd/java/source/cynosure/Cynosure-java.txt
10 * Original comments and copyright:
13 * A Java implementation of Stephen Linhart's Cynosure screen-saver as a
16 * Header: /home/ogd/lib/cvs/aoaioxxysz/graphics/Cynosure.java,v 1.2 1996/08/02 02:41:21 ogd Exp
18 * ozymandias G desiderata <ogd@organic.com>
23 * Copyright 1996 ozymandias G desiderata. Title, ownership rights, and
24 * intellectual property rights in and to this software remain with
25 * ozymandias G desiderata. This software may be copied, modified,
26 * or used as long as this copyright is retained. Use this code at your
31 * Log: Cynosure.java,v
32 * Revision 1.2 1996/08/02 02:41:21 ogd
33 * Added a few more comments, fixed messed-up header.
35 * Revision 1.1.1.1 1996/08/02 02:30:45 ogd
39 #include "screenhack.h"
41 /* #define DO_STIPPLE */
55 int fg_pixel, bg_pixel;
56 GC fg_gc, bg_gc, shadow_gc;
59 int curBase; /* color progression */
61 int elevation; /* offset of dropshadow */
62 int sway; /* time until base color changed */
63 int timeLeft; /* until base color used */
64 int tweak; /* amount of color variance */
66 int iterations, i, delay;
67 XWindowAttributes xgwa;
72 * The smallest size for an individual cell.
74 #define MINCELLSIZE 16
77 * The narrowest a rectangle can be.
82 * Every so often genNewColor() generates a completely random
83 * color. This variable sets how frequently that happens. It's
84 * currently set to happen 1% of the time.
88 #define THRESHOLD 100 /*0.01*/
90 static void paint(struct state *st);
91 static int genNewColor(struct state *st);
92 static int genConstrainedColor(struct state *st, int base, int tweak);
93 static int c_tweak(struct state *st, int base, int tweak);
97 cynosure_init (Display *d, Window w)
99 struct state *st = (struct state *) calloc (1, sizeof(*st));
106 st->curBase = st->curColor;
107 st->shadowWidth = get_integer_resource (st->dpy, "shadowWidth", "Integer");
108 st->elevation = get_integer_resource (st->dpy, "elevation", "Integer");
109 st->sway = get_integer_resource (st->dpy, "sway", "Integer");
110 st->tweak = get_integer_resource (st->dpy, "tweak", "Integer");
111 st->gridSize = get_integer_resource (st->dpy, "gridSize", "Integer");
114 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
116 st->ncolors = get_integer_resource (st->dpy, "colors", "Colors");
117 if (st->ncolors < 2) st->ncolors = 2;
118 if (st->ncolors <= 2) mono_p = True;
123 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
128 make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
129 st->colors, &st->ncolors,
131 if (st->ncolors <= 2) {
134 if (st->colors) free(st->colors);
139 st->bg_pixel = get_pixel_resource(st->dpy,
140 st->xgwa.colormap, "background", "Background");
141 st->fg_pixel = get_pixel_resource(st->dpy,
142 st->xgwa.colormap, "foreground", "Foreground");
144 gcv.foreground = st->fg_pixel;
145 st->fg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
146 gcv.foreground = st->bg_pixel;
147 st->bg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
150 gcv.fill_style = FillStippled;
151 gcv.stipple = XCreateBitmapFromData(st->dpy, st->window, "\125\252", 8, 2);
152 st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground|GCFillStyle|GCStipple, &gcv);
153 XFreePixmap(st->dpy, gcv.stipple);
155 #else /* !DO_STIPPLE */
156 st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
158 # ifdef HAVE_JWXYZ /* allow non-opaque alpha components in pixel values */
159 jwxyz_XSetAlphaAllowed (st->dpy, st->shadow_gc, True);
165 st->ncolors2 = st->ncolors;
166 st->colors2 = (XColor *) malloc(sizeof(*st->colors2) * (st->ncolors2+1));
168 for (i = 0; i < st->ncolors2; i++)
171 /* give a non-opaque alpha to the shadow colors */
172 unsigned long pixel = st->colors[i].pixel;
173 unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
174 unsigned long a = (0x77777777 & amask);
175 pixel = (pixel & (~amask)) | a;
176 st->colors2[i].pixel = pixel;
177 # else /* !HAVE_JWXYZ */
180 rgb_to_hsv (st->colors[i].red,
187 &st->colors2[i].green,
188 &st->colors2[i].blue);
189 st->colors2[i].pixel = st->colors[i].pixel;
190 XAllocColor (st->dpy, st->xgwa.colormap, &st->colors2[i]);
191 # endif /* !HAVE_JWXYZ */
194 # endif /* !DO_STIPPLE */
196 st->delay = get_integer_resource (st->dpy, "delay", "Delay");
197 st->iterations = get_integer_resource (st->dpy, "iterations", "Iterations");
203 cynosure_draw (Display *dpy, Window window, void *closure)
205 struct state *st = (struct state *) closure;
206 if (st->iterations > 0 && ++st->i >= st->iterations)
210 XSetWindowBackground(st->dpy, st->window,
211 st->colors[random() % st->ncolors].pixel);
212 XClearWindow(st->dpy, st->window);
221 * paint adds a new layer of multicolored rectangles within a grid of
222 * randomly generated size. Each row of rectangles is the same color,
223 * but colors vary slightly from row to row. Each rectangle is placed
224 * within a regularly-sized cell, but each rectangle is sized and
225 * placed randomly within that cell.
227 * @param g the Graphics coordinate in which to draw
230 static void paint(struct state *st)
233 int cellsWide, cellsHigh, cellWidth, cellHeight;
234 int width = st->xgwa.width;
235 int height = st->xgwa.height;
237 /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
239 cellsWide = c_tweak(st, st->gridSize, st->gridSize / 2);
240 /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
242 cellsHigh = c_tweak(st, st->gridSize, st->gridSize / 2);
243 /* How wide each cell in the grid is */
244 cellWidth = width / cellsWide;
245 /* How tall each cell in the grid is */
246 cellHeight = height / cellsHigh;
248 /* Ensure that each cell is above a certain minimum size */
250 if (cellWidth < MINCELLSIZE) {
251 cellWidth = MINCELLSIZE;
252 cellsWide = width / cellWidth;
255 if (cellHeight < MINCELLSIZE) {
256 cellHeight = MINCELLSIZE;
257 cellsHigh = width / cellWidth;
260 /* fill the grid with randomly-generated cells */
261 for(i = 0; i < cellsHigh; i++) {
264 /* Each row is a different color, randomly generated (but constrained) */
267 int c = genNewColor(st);
268 XSetForeground(st->dpy, st->fg_gc, st->colors[c].pixel);
271 XSetForeground(st->dpy, st->shadow_gc, st->colors2[c].pixel);
275 for(j = 0; j < cellsWide; j++) {
276 int curWidth, curHeight, curX, curY;
278 /* Generate a random height for a rectangle and make sure that */
279 /* it's above a certain minimum size */
280 curHeight = random() % (cellHeight - st->shadowWidth);
281 if (curHeight < MINRECTSIZE)
282 curHeight = MINRECTSIZE;
283 /* Generate a random width for a rectangle and make sure that
284 it's above a certain minimum size */
285 curWidth = random() % (cellWidth - st->shadowWidth);
286 if (curWidth < MINRECTSIZE)
287 curWidth = MINRECTSIZE;
288 /* Figure out a random place to locate the rectangle within the
290 curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
292 curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) -
295 /* Draw the shadow */
296 if (st->elevation > 0)
297 XFillRectangle(st->dpy, st->window, st->shadow_gc,
298 curX + st->elevation, curY + st->elevation,
299 curWidth, curHeight);
302 if (st->shadowWidth > 0)
303 XFillRectangle(st->dpy, st->window, st->bg_gc,
304 curX + st->shadowWidth, curY + st->shadowWidth,
305 curWidth, curHeight);
307 XFillRectangle(st->dpy, st->window, st->fg_gc, curX, curY, curWidth, curHeight);
309 /* Draw a 1-pixel black border around the rectangle */
310 XDrawRectangle(st->dpy, st->window, st->bg_gc, curX, curY, curWidth, curHeight);
318 * genNewColor returns a new color, gradually mutating the colors and
319 * occasionally returning a totally random color, just for variety.
321 * @return the new color
323 static int genNewColor(struct state *st)
325 /* These lines handle "sway", or the gradual random changing of */
326 /* colors. After genNewColor() has been called a given number of */
327 /* times (specified by a random permutation of the tweak variable), */
328 /* take whatever color has been most recently randomly generated and */
329 /* make it the new base color. */
330 if (st->timeLeft == 0) {
331 st->timeLeft = c_tweak(st, st->sway, st->sway / 3);
332 st->curColor = st->curBase;
337 /* If a randomly generated number is less than the threshold value,
338 produce a "sport" color value that is completely unrelated to the
340 if (0 == (random() % THRESHOLD)) {
341 return (random() % st->ncolors);
343 st->curBase = genConstrainedColor(st, st->curColor, st->tweak);
350 * genConstrainedColor creates a random new color within a certain
351 * range of an existing color. Right now this works with RGB color
352 * values, but a future version of the program will most likely use HSV
353 * colors, which should generate a more pleasing progression of values.
355 * @param base the color on which the new color will be based
356 * @param tweak the amount that the new color can be tweaked
357 * @return a new constrained color
360 static int genConstrainedColor(struct state *st, int base, int tweak)
362 int i = 1 + (random() % st->tweak);
365 i = (base + i) % st->ncolors;
372 * Utility function to generate a tweaked color value
374 * @param base the byte value on which the color is based
375 * @param tweak the amount the value will be skewed
377 * @return the tweaked byte
379 static int c_tweak(struct state *st, int base, int tweak)
381 int ranTweak = (random() % (2 * tweak));
382 int n = (base + (ranTweak - tweak));
384 return (n < 255 ? n : 255);
388 cynosure_reshape (Display *dpy, Window window, void *closure,
389 unsigned int w, unsigned int h)
391 struct state *st = (struct state *) closure;
397 cynosure_event (Display *dpy, Window window, void *closure, XEvent *event)
399 struct state *st = (struct state *) closure;
400 if (screenhack_event_helper (dpy, window, event))
402 st->i = st->iterations;
409 cynosure_free (Display *dpy, Window window, void *closure)
411 struct state *st = (struct state *) closure;
416 static const char *cynosure_defaults [] = {
417 ".background: black",
418 ".foreground: white",
429 "*ignoreRotation: True",
434 static XrmOptionDescRec cynosure_options [] = {
435 { "-delay", ".delay", XrmoptionSepArg, 0 },
436 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
437 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
442 XSCREENSAVER_MODULE ("Cynosure", cynosure)