source: trunk/third/xscreensaver/hacks/cynosure.c @ 12203

Revision 12203, 10.5 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12202, which included commits to RCS files with non-trunk default branches.
Line 
1/* cynosure --- draw some rectangles
2 *
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>
5 *
6 * Original version:
7 *   http://www.organic.com/staff/ogd/java/cynosure.html
8 *   http://www.organic.com/staff/ogd/java/source/cynosure/Cynosure-java.txt
9 *
10 * Original comments and copyright:
11 *
12 *   Cynosure.java
13 *   A Java implementation of Stephen Linhart's Cynosure screen-saver as a
14 *   drop-in class.
15 *
16 *   Header: /home/ogd/lib/cvs/aoaioxxysz/graphics/Cynosure.java,v 1.2 1996/08/02 02:41:21 ogd Exp
17 *
18 *   ozymandias G desiderata <ogd@organic.com>
19 *   Thu Aug  1 1996
20 *
21 *   COPYRIGHT NOTICE
22 *
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
27 *   own risk.
28 *
29 *   Revision: 1.2
30 *
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.
34 *
35 *   Revision 1.1.1.1  1996/08/02 02:30:45  ogd
36 *   First version
37 */
38
39#include "screenhack.h"
40static Display *dpy;
41static Window window;
42static XColor *colors;
43static int ncolors;
44static int fg_pixel, bg_pixel;
45static GC fg_gc, bg_gc, shadow_gc;
46
47static void paint(void);
48static int genNewColor(void);
49static int genConstrainedColor(int base, int tweak);
50static int c_tweak(int base, int tweak);
51
52/**
53 * The current color that is being tweaked to create the
54 * rectangles.
55 **/
56static int curColor;
57
58/**
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).
62 **/
63static int curBase;
64
65/**
66 * The width of the right and bottom edges of the rectangles.
67 **/
68static int   shadowWidth;
69
70/* The offset of the dropshadow beneath the rectangles. */
71static int   elevation;
72
73/**
74 * The approximate amount of time that will elapse before the base
75 * color is permanently changed.
76 *
77 * @see #tweak
78 **/
79static int   sway;
80
81/**
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).
85 **/
86static int   timeLeft;
87
88/**
89 * The amount by which the color of the polygons drawn will vary.
90 *
91 * @see #sway;
92 **/
93static int   tweak;
94
95/**
96 * The smallest size for an individual cell.
97 **/
98#define MINCELLSIZE 16
99
100/**
101 * The narrowest a rectangle can be.
102 **/
103#define MINRECTSIZE 6
104
105/**
106 * The size of the grid that the rectangles are placed within.
107 **/
108static int gridSize;
109
110/**
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.
114 *
115 * @see #genNewColor
116 **/
117#define THRESHOLD 100 /*0.01*/
118
119
120char *progclass = "Cynosure";
121char *defaults [] = {
122  ".background:         black",
123  ".foreground:         white",
124  "*delay:              500000",
125  "*colors:             128",
126  "*iterations:         100",
127  "*shadowWidth:        2",
128  "*elevation:          5",
129  "*sway:               30",
130  "*tweak:              20",
131  "*gridSize:           12",
132  0
133};
134
135XrmOptionDescRec options [] = {
136  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
137  { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
138  { "-iterations",      ".iterations",  XrmoptionSepArg, 0 },
139  { 0, 0, 0, 0 }
140};
141
142
143void screenhack(Display *d, Window w)
144{
145  XWindowAttributes xgwa;
146  XGCValues gcv;
147  int delay;
148  int i, iterations;
149
150  dpy = d;
151  window = w;
152
153  curColor    = 0;
154  curBase     = curColor;
155  shadowWidth = get_integer_resource ("shadowWidth", "Integer");
156  elevation   = get_integer_resource ("elevation", "Integer");
157  sway        = get_integer_resource ("sway", "Integer");
158  tweak       = get_integer_resource ("tweak", "Integer");
159  gridSize    = get_integer_resource ("gridSize", "Integer");
160  timeLeft    = 0;
161
162  XGetWindowAttributes (dpy, window, &xgwa);
163
164  ncolors = get_integer_resource ("colors", "Colors");
165  if (ncolors < 2) ncolors = 2;
166  if (ncolors <= 2) mono_p = True;
167
168  if (mono_p)
169    colors = 0;
170  else
171    colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
172
173  if (mono_p)
174    ;
175  else {
176    make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
177                          True, 0, True);
178    if (ncolors <= 2) {
179      mono_p = True;
180      ncolors = 2;
181      if (colors) free(colors);
182      colors = 0;
183    }
184  }
185
186  bg_pixel = get_pixel_resource("background", "Background", dpy,
187                                xgwa.colormap);
188  fg_pixel = get_pixel_resource("foreground", "Foreground", dpy,
189                                xgwa.colormap);
190
191  gcv.foreground = fg_pixel;
192  fg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
193  gcv.foreground = bg_pixel;
194  bg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
195
196  gcv.fill_style = FillStippled;
197  gcv.stipple = XCreateBitmapFromData(dpy, window, "\125\252", 8, 2);
198  shadow_gc = XCreateGC(dpy, window, GCForeground|GCFillStyle|GCStipple, &gcv);
199  XFreePixmap(dpy, gcv.stipple);
200
201  delay = get_integer_resource ("delay", "Delay");
202  iterations = get_integer_resource ("iterations", "Iterations");
203
204  i = 0;
205  while (1)
206    {
207      if (iterations > 0 && ++i >= iterations)
208        {
209          i = 0;
210          if (!mono_p)
211            XSetWindowBackground(dpy, window,
212                                 colors[random() % ncolors].pixel);
213          XClearWindow(dpy, window);
214        }
215      paint();
216      XSync(dpy, False);
217      screenhack_handle_events (dpy);
218      if (delay)
219        usleep(delay);
220    }
221}
222
223/**
224 * paint adds a new layer of multicolored rectangles within a grid of
225 * randomly generated size. Each row of rectangles is the same color,
226 * but colors vary slightly from row to row. Each rectangle is placed
227 * within a regularly-sized cell, but each rectangle is sized and
228 * placed randomly within that cell.
229 *
230 * @param g      the Graphics coordinate in which to draw
231 * @see #genNewColor
232 **/
233static void paint(void)
234{
235    int i;
236    int cellsWide, cellsHigh, cellWidth, cellHeight;
237    static int width, height;
238    static int size_check = 1;
239
240    if (--size_check <= 0)
241      {
242        XWindowAttributes xgwa;
243        XGetWindowAttributes (dpy, window, &xgwa);
244        width = xgwa.width;
245        height = xgwa.height;
246        size_check = 1000;
247      }
248
249    /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
250     */
251    cellsWide  = c_tweak(gridSize, gridSize / 2);
252    /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
253     */
254    cellsHigh  = c_tweak(gridSize, gridSize / 2);
255    /* How wide each cell in the grid is */
256    cellWidth  = width  / cellsWide;
257    /* How tall each cell in the grid is */
258    cellHeight = height / cellsHigh;
259
260    /* Ensure that each cell is above a certain minimum size */
261
262    if (cellWidth < MINCELLSIZE) {
263      cellWidth  = MINCELLSIZE;
264      cellsWide  = width / cellWidth;
265    }
266
267    if (cellHeight < MINCELLSIZE) {
268      cellHeight = MINCELLSIZE;
269      cellsHigh  = width / cellWidth;
270    }
271
272    /* fill the grid with randomly-generated cells */
273    for(i = 0; i < cellsHigh; i++) {
274      int j;
275
276      /* Each row is a different color, randomly generated (but constrained) */
277      if (!mono_p)
278        {
279          int c = genNewColor();
280          XSetForeground(dpy, fg_gc, colors[c].pixel);
281        }
282
283      for(j = 0; j < cellsWide; j++) {
284        int curWidth, curHeight, curX, curY;
285
286        /* Generate a random height for a rectangle and make sure that */
287        /* it's above a certain minimum size */
288        curHeight = random() % (cellHeight - shadowWidth);
289        if (curHeight < MINRECTSIZE)
290          curHeight = MINRECTSIZE;
291        /* Generate a random width for a rectangle and make sure that
292           it's above a certain minimum size */
293        curWidth  = random() % (cellWidth  - shadowWidth);
294        if (curWidth < MINRECTSIZE)
295          curWidth = MINRECTSIZE;
296        /* Figure out a random place to locate the rectangle within the
297           cell */
298        curY      = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
299                                                    shadowWidth));
300        curX      = (j * cellWidth) +  (random() % ((cellWidth  - curWidth) -
301                                                    shadowWidth));
302
303        /* Draw the shadow */
304        if (elevation > 0)
305          XFillRectangle(dpy, window, shadow_gc,
306                         curX + elevation, curY + elevation,
307                         curWidth, curHeight);
308
309        /* Draw the edge */
310        if (shadowWidth > 0)
311          XFillRectangle(dpy, window, bg_gc,
312                         curX + shadowWidth, curY + shadowWidth,
313                         curWidth, curHeight);
314
315        XFillRectangle(dpy, window, fg_gc, curX, curY, curWidth, curHeight);
316
317        /* Draw a 1-pixel black border around the rectangle */
318        XDrawRectangle(dpy, window, bg_gc, curX, curY, curWidth, curHeight);
319      }
320
321    }
322}
323
324
325/**
326 * genNewColor returns a new color, gradually mutating the colors and
327 * occasionally returning a totally random color, just for variety.
328 *
329 * @return the new color
330 **/
331static int genNewColor(void)
332{
333    /* These lines handle "sway", or the gradual random changing of */
334    /* colors. After genNewColor() has been called a given number of */
335    /* times (specified by a random permutation of the tweak variable), */
336    /* take whatever color has been most recently randomly generated and */
337    /* make it the new base color. */
338    if (timeLeft == 0) {
339      timeLeft = c_tweak(sway, sway / 3);
340      curColor = curBase;
341    } else {
342      timeLeft--;
343    }
344     
345    /* If a randomly generated number is less than the threshold value,
346       produce a "sport" color value that is completely unrelated to the
347       current palette. */
348    if (0 == (random() % THRESHOLD)) {
349      return (random() % ncolors);
350    } else {
351      curBase = genConstrainedColor(curColor, tweak);
352      return curBase;
353    }
354
355}
356
357/**
358 * genConstrainedColor creates a random new color within a certain
359 * range of an existing color. Right now this works with RGB color
360 * values, but a future version of the program will most likely use HSV
361 * colors, which should generate a more pleasing progression of values.
362 *
363 * @param base  the color on which the new color will be based
364 * @param tweak the amount that the new color can be tweaked
365 * @return a new constrained color
366 * @see #genNewColor
367 **/
368static int genConstrainedColor(int base, int tweak)
369{
370    int i = 1 + (random() % tweak);
371    if (random() & 1)
372      i = -i;
373    i = (base + i) % ncolors;
374    while (i < 0)
375      i += ncolors;
376    return i;
377}
378
379/**
380 * Utility function to generate a tweaked color value
381 *
382 * @param  base   the byte value on which the color is based
383 * @param  tweak  the amount the value will be skewed
384 * @see    #tweak
385 * @return the tweaked byte
386 **/
387static int c_tweak(int base, int tweak)
388{
389    int ranTweak = (random() % (2 * tweak));
390    int n = (base + (ranTweak - tweak));
391    if (n < 0) n = -n;
392    return (n < 255 ? n : 255);
393}
Note: See TracBrowser for help on using the repository browser.