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@netscape.com>
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"
42 static XColor *colors;
44 static int fg_pixel, bg_pixel;
45 static GC fg_gc, bg_gc, shadow_gc;
47 static void paint(void);
48 static int genNewColor(void);
49 static int genConstrainedColor(int base, int tweak);
50 static int c_tweak(int base, int tweak);
53 * The current color that is being tweaked to create the
59 * A variable used for the progression of the colors (yes, I know
60 * that's a lame explanation, but if your read the source, it should
61 * become obvious what I'm doing with this variable).
66 * The width of the right and bottom edges of the rectangles.
68 static int shadowWidth;
70 /* The offset of the dropshadow beneath the rectangles. */
74 * The approximate amount of time that will elapse before the base
75 * color is permanently changed.
82 * The counter of time left until the base color value used. This class
83 * variable is necessary because Java doesn't support static method
84 * variables (grr grr).
89 * The amount by which the color of the polygons drawn will vary.
96 * The smallest size for an individual cell.
98 #define MINCELLSIZE 16
101 * The narrowest a rectangle can be.
103 #define MINRECTSIZE 6
106 * The size of the grid that the rectangles are placed within.
111 * Every so often genNewColor() generates a completely random
112 * color. This variable sets how frequently that happens. It's
113 * currently set to happen 1% of the time.
117 #define THRESHOLD 100 /*0.01*/
120 char *progclass = "Cynosure";
121 char *defaults [] = {
122 "Cynosure.background: black", /* to placate SGI */
134 XrmOptionDescRec options [] = {
135 { "-delay", ".delay", XrmoptionSepArg, 0 },
136 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
137 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
142 void screenhack(Display *d, Window w)
144 XWindowAttributes xgwa;
154 shadowWidth = get_integer_resource ("shadowWidth", "Integer");
155 elevation = get_integer_resource ("elevation", "Integer");
156 sway = get_integer_resource ("sway", "Integer");
157 tweak = get_integer_resource ("tweak", "Integer");
158 gridSize = get_integer_resource ("gridSize", "Integer");
161 XGetWindowAttributes (dpy, window, &xgwa);
163 ncolors = get_integer_resource ("colors", "Colors");
164 if (ncolors < 2) ncolors = 2;
165 if (ncolors <= 2) mono_p = True;
170 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
175 make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
180 if (colors) free(colors);
185 bg_pixel = get_pixel_resource("background", "Background", dpy,
187 fg_pixel = get_pixel_resource("foreground", "Foreground", dpy,
190 gcv.foreground = fg_pixel;
191 fg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
192 gcv.foreground = bg_pixel;
193 bg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
195 gcv.fill_style = FillStippled;
196 gcv.stipple = XCreateBitmapFromData(dpy, window, "\125\252", 8, 2);
197 shadow_gc = XCreateGC(dpy, window, GCForeground|GCFillStyle|GCStipple, &gcv);
198 XFreePixmap(dpy, gcv.stipple);
200 delay = get_integer_resource ("delay", "Delay");
201 iterations = get_integer_resource ("iterations", "Iterations");
205 if (iterations > 0 && ++i >= iterations)
209 XSetWindowBackground(dpy, window,
210 colors[random() % ncolors].pixel);
211 XClearWindow(dpy, 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(void)
233 int cellsWide, cellsHigh, cellWidth, cellHeight;
234 static int width, height;
235 static int size_check = 1;
237 if (--size_check <= 0)
239 XWindowAttributes xgwa;
240 XGetWindowAttributes (dpy, window, &xgwa);
242 height = xgwa.height;
246 /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
248 cellsWide = c_tweak(gridSize, gridSize / 2);
249 /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
251 cellsHigh = c_tweak(gridSize, gridSize / 2);
252 /* How wide each cell in the grid is */
253 cellWidth = width / cellsWide;
254 /* How tall each cell in the grid is */
255 cellHeight = height / cellsHigh;
257 /* Ensure that each cell is above a certain minimum size */
259 if (cellWidth < MINCELLSIZE) {
260 cellWidth = MINCELLSIZE;
261 cellsWide = width / cellWidth;
264 if (cellHeight < MINCELLSIZE) {
265 cellHeight = MINCELLSIZE;
266 cellsHigh = width / cellWidth;
269 /* fill the grid with randomly-generated cells */
270 for(i = 0; i < cellsHigh; i++) {
273 /* Each row is a different color, randomly generated (but constrained) */
276 int c = genNewColor();
277 XSetForeground(dpy, fg_gc, colors[c].pixel);
280 for(j = 0; j < cellsWide; j++) {
281 int curWidth, curHeight, curX, curY;
283 /* Generate a random height for a rectangle and make sure that */
284 /* it's above a certain minimum size */
285 curHeight = random() % (cellHeight - shadowWidth);
286 if (curHeight < MINRECTSIZE)
287 curHeight = MINRECTSIZE;
288 /* Generate a random width for a rectangle and make sure that
289 it's above a certain minimum size */
290 curWidth = random() % (cellWidth - shadowWidth);
291 if (curWidth < MINRECTSIZE)
292 curWidth = MINRECTSIZE;
293 /* Figure out a random place to locate the rectangle within the
295 curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
297 curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) -
300 /* Draw the shadow */
302 XFillRectangle(dpy, window, shadow_gc,
303 curX + elevation, curY + elevation,
304 curWidth, curHeight);
308 XFillRectangle(dpy, window, bg_gc,
309 curX + shadowWidth, curY + shadowWidth,
310 curWidth, curHeight);
312 XFillRectangle(dpy, window, fg_gc, curX, curY, curWidth, curHeight);
314 /* Draw a 1-pixel black border around the rectangle */
315 XDrawRectangle(dpy, window, bg_gc, curX, curY, curWidth, curHeight);
323 * genNewColor returns a new color, gradually mutating the colors and
324 * occasionally returning a totally random color, just for variety.
326 * @return the new color
328 static int genNewColor(void)
330 /* These lines handle "sway", or the gradual random changing of */
331 /* colors. After genNewColor() has been called a given number of */
332 /* times (specified by a random permutation of the tweak variable), */
333 /* take whatever color has been most recently randomly generated and */
334 /* make it the new base color. */
336 timeLeft = c_tweak(sway, sway / 3);
342 /* If a randomly generated number is less than the threshold value,
343 produce a "sport" color value that is completely unrelated to the
345 if (0 == (random() % THRESHOLD)) {
346 return (random() % ncolors);
348 curBase = genConstrainedColor(curColor, tweak);
355 * genConstrainedColor creates a random new color within a certain
356 * range of an existing color. Right now this works with RGB color
357 * values, but a future version of the program will most likely use HSV
358 * colors, which should generate a more pleasing progression of values.
360 * @param base the color on which the new color will be based
361 * @param tweak the amount that the new color can be tweaked
362 * @return a new constrained color
365 static int genConstrainedColor(int base, int tweak)
367 int i = 1 + (random() % tweak);
370 i = (base + i) % ncolors;
377 * Utility function to generate a tweaked color value
379 * @param base the byte value on which the color is based
380 * @param tweak the amount the value will be skewed
382 * @return the tweaked byte
384 static int c_tweak(int base, int tweak)
386 int ranTweak = (random() % (2 * tweak));
387 int n = (base + (ranTweak - tweak));
389 return (n < 255 ? n : 255);