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->dpy, st->xgwa.visual, st->xgwa.colormap, st->colors, &st->ncolors,
130 if (st->ncolors <= 2) {
133 if (st->colors) free(st->colors);
138 st->bg_pixel = get_pixel_resource(st->dpy,
139 st->xgwa.colormap, "background", "Background");
140 st->fg_pixel = get_pixel_resource(st->dpy,
141 st->xgwa.colormap, "foreground", "Foreground");
143 gcv.foreground = st->fg_pixel;
144 st->fg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
145 gcv.foreground = st->bg_pixel;
146 st->bg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
149 gcv.fill_style = FillStippled;
150 gcv.stipple = XCreateBitmapFromData(st->dpy, st->window, "\125\252", 8, 2);
151 st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground|GCFillStyle|GCStipple, &gcv);
152 XFreePixmap(st->dpy, gcv.stipple);
154 #else /* !DO_STIPPLE */
155 st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
157 # ifdef HAVE_COCOA /* allow non-opaque alpha components in pixel values */
158 jwxyz_XSetAlphaAllowed (st->dpy, st->shadow_gc, True);
164 st->ncolors2 = st->ncolors;
165 st->colors2 = (XColor *) malloc(sizeof(*st->colors2) * (st->ncolors2+1));
167 for (i = 0; i < st->ncolors2; i++)
170 /* give a non-opaque alpha to the shadow colors */
171 unsigned long pixel = st->colors[i].pixel;
172 unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
173 unsigned long a = (0x77777777 & amask);
174 pixel = (pixel & (~amask)) | a;
175 st->colors2[i].pixel = pixel;
176 # else /* !HAVE_COCOA */
179 rgb_to_hsv (st->colors[i].red,
186 &st->colors2[i].green,
187 &st->colors2[i].blue);
188 st->colors2[i].pixel = st->colors[i].pixel;
189 XAllocColor (st->dpy, st->xgwa.colormap, &st->colors2[i]);
190 # endif /* !HAVE_COCOA */
193 # endif /* !DO_STIPPLE */
195 st->delay = get_integer_resource (st->dpy, "delay", "Delay");
196 st->iterations = get_integer_resource (st->dpy, "iterations", "Iterations");
202 cynosure_draw (Display *dpy, Window window, void *closure)
204 struct state *st = (struct state *) closure;
205 if (st->iterations > 0 && ++st->i >= st->iterations)
209 XSetWindowBackground(st->dpy, st->window,
210 st->colors[random() % st->ncolors].pixel);
211 XClearWindow(st->dpy, st->window);
220 * paint adds a new layer of multicolored rectangles within a grid of
221 * randomly generated size. Each row of rectangles is the same color,
222 * but colors vary slightly from row to row. Each rectangle is placed
223 * within a regularly-sized cell, but each rectangle is sized and
224 * placed randomly within that cell.
226 * @param g the Graphics coordinate in which to draw
229 static void paint(struct state *st)
232 int cellsWide, cellsHigh, cellWidth, cellHeight;
233 int width = st->xgwa.width;
234 int height = st->xgwa.height;
236 /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
238 cellsWide = c_tweak(st, st->gridSize, st->gridSize / 2);
239 /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
241 cellsHigh = c_tweak(st, st->gridSize, st->gridSize / 2);
242 /* How wide each cell in the grid is */
243 cellWidth = width / cellsWide;
244 /* How tall each cell in the grid is */
245 cellHeight = height / cellsHigh;
247 /* Ensure that each cell is above a certain minimum size */
249 if (cellWidth < MINCELLSIZE) {
250 cellWidth = MINCELLSIZE;
251 cellsWide = width / cellWidth;
254 if (cellHeight < MINCELLSIZE) {
255 cellHeight = MINCELLSIZE;
256 cellsHigh = width / cellWidth;
259 /* fill the grid with randomly-generated cells */
260 for(i = 0; i < cellsHigh; i++) {
263 /* Each row is a different color, randomly generated (but constrained) */
266 int c = genNewColor(st);
267 XSetForeground(st->dpy, st->fg_gc, st->colors[c].pixel);
270 XSetForeground(st->dpy, st->shadow_gc, st->colors2[c].pixel);
274 for(j = 0; j < cellsWide; j++) {
275 int curWidth, curHeight, curX, curY;
277 /* Generate a random height for a rectangle and make sure that */
278 /* it's above a certain minimum size */
279 curHeight = random() % (cellHeight - st->shadowWidth);
280 if (curHeight < MINRECTSIZE)
281 curHeight = MINRECTSIZE;
282 /* Generate a random width for a rectangle and make sure that
283 it's above a certain minimum size */
284 curWidth = random() % (cellWidth - st->shadowWidth);
285 if (curWidth < MINRECTSIZE)
286 curWidth = MINRECTSIZE;
287 /* Figure out a random place to locate the rectangle within the
289 curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
291 curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) -
294 /* Draw the shadow */
295 if (st->elevation > 0)
296 XFillRectangle(st->dpy, st->window, st->shadow_gc,
297 curX + st->elevation, curY + st->elevation,
298 curWidth, curHeight);
301 if (st->shadowWidth > 0)
302 XFillRectangle(st->dpy, st->window, st->bg_gc,
303 curX + st->shadowWidth, curY + st->shadowWidth,
304 curWidth, curHeight);
306 XFillRectangle(st->dpy, st->window, st->fg_gc, curX, curY, curWidth, curHeight);
308 /* Draw a 1-pixel black border around the rectangle */
309 XDrawRectangle(st->dpy, st->window, st->bg_gc, curX, curY, curWidth, curHeight);
317 * genNewColor returns a new color, gradually mutating the colors and
318 * occasionally returning a totally random color, just for variety.
320 * @return the new color
322 static int genNewColor(struct state *st)
324 /* These lines handle "sway", or the gradual random changing of */
325 /* colors. After genNewColor() has been called a given number of */
326 /* times (specified by a random permutation of the tweak variable), */
327 /* take whatever color has been most recently randomly generated and */
328 /* make it the new base color. */
329 if (st->timeLeft == 0) {
330 st->timeLeft = c_tweak(st, st->sway, st->sway / 3);
331 st->curColor = st->curBase;
336 /* If a randomly generated number is less than the threshold value,
337 produce a "sport" color value that is completely unrelated to the
339 if (0 == (random() % THRESHOLD)) {
340 return (random() % st->ncolors);
342 st->curBase = genConstrainedColor(st, st->curColor, st->tweak);
349 * genConstrainedColor creates a random new color within a certain
350 * range of an existing color. Right now this works with RGB color
351 * values, but a future version of the program will most likely use HSV
352 * colors, which should generate a more pleasing progression of values.
354 * @param base the color on which the new color will be based
355 * @param tweak the amount that the new color can be tweaked
356 * @return a new constrained color
359 static int genConstrainedColor(struct state *st, int base, int tweak)
361 int i = 1 + (random() % st->tweak);
364 i = (base + i) % st->ncolors;
371 * Utility function to generate a tweaked color value
373 * @param base the byte value on which the color is based
374 * @param tweak the amount the value will be skewed
376 * @return the tweaked byte
378 static int c_tweak(struct state *st, int base, int tweak)
380 int ranTweak = (random() % (2 * tweak));
381 int n = (base + (ranTweak - tweak));
383 return (n < 255 ? n : 255);
387 cynosure_reshape (Display *dpy, Window window, void *closure,
388 unsigned int w, unsigned int h)
390 struct state *st = (struct state *) closure;
396 cynosure_event (Display *dpy, Window window, void *closure, XEvent *event)
402 cynosure_free (Display *dpy, Window window, void *closure)
404 struct state *st = (struct state *) closure;
409 static const char *cynosure_defaults [] = {
410 ".background: black",
411 ".foreground: white",
424 static XrmOptionDescRec cynosure_options [] = {
425 { "-delay", ".delay", XrmoptionSepArg, 0 },
426 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
427 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
432 XSCREENSAVER_MODULE ("Cynosure", cynosure)