b4f4aa89068b0aa722146b68bd373d3ed9115b0e
[xscreensaver] / hacks / rorschach.c
1 /* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  *
11  * 19971004: Johannes Keukelaar <johannes@nada.kth.se>: Use helix screen
12  *           eraser.
13  */
14
15 #include "screenhack.h"
16 #include "erase.h"
17
18 struct state {
19   GC draw_gc;
20   unsigned int default_fg_pixel;
21   int iterations, offset;
22   Bool xsym, ysym;
23   int sleep_time;
24   int xlim, ylim;
25   XColor color;
26   int current_x, current_y, remaining_iterations;
27   eraser_state *eraser;
28 };
29
30
31 static void *
32 rorschach_init (Display *dpy, Window window)
33 {
34   struct state *st = (struct state *) calloc (1, sizeof(*st));
35   XGCValues gcv;
36   Colormap cmap;
37   XWindowAttributes xgwa;
38   XGetWindowAttributes (dpy, window, &xgwa);
39   cmap = xgwa.colormap;
40   gcv.foreground = st->default_fg_pixel =
41     get_pixel_resource (dpy, cmap, "foreground", "Foreground");
42   st->draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
43   gcv.foreground = get_pixel_resource (dpy, cmap, "background", "Background");
44   st->iterations = get_integer_resource (dpy, "iterations", "Integer");
45   st->offset = get_integer_resource (dpy, "offset", "Integer");
46   if (st->offset <= 0) st->offset = 3;
47   if (st->iterations < 10) st->iterations = 10;
48   st->sleep_time = get_integer_resource (dpy, "delay", "Delay");
49   st->xsym = get_boolean_resource (dpy, "xsymmetry", "Symmetry");
50   st->ysym = get_boolean_resource (dpy, "ysymmetry", "Symmetry");
51   st->remaining_iterations = -1;
52   st->color.pixel = 0;
53   return st;
54 }
55
56 static void
57 rorschach_reshape (Display *dpy, Window window, void *closure,
58                    unsigned int width, unsigned int height)
59 {
60   struct state *st = (struct state *) closure;
61   st->xlim = width;
62   st->ylim = height;
63 }
64
65
66 static void
67 rorschach_draw_start (Display *dpy, Window window, struct state *st)
68 {
69   Colormap cmap;
70   XWindowAttributes xgwa;
71
72   XGetWindowAttributes (dpy, window, &xgwa);
73   st->xlim = xgwa.width;
74   st->ylim = xgwa.height;
75   cmap = xgwa.colormap;
76
77   if (st->color.pixel) XFreeColors (dpy, cmap, &st->color.pixel, 1, 0);
78
79   if (! mono_p)
80     hsv_to_rgb (random()%360, 1.0, 1.0, &st->color.red, &st->color.green, &st->color.blue);
81   if ((!mono_p) && XAllocColor (dpy, cmap, &st->color))
82     XSetForeground (dpy, st->draw_gc, st->color.pixel);
83   else
84     XSetForeground (dpy, st->draw_gc, st->default_fg_pixel);
85
86   st->current_x = st->xlim/2;
87   st->current_y = st->ylim/2;
88   st->remaining_iterations = st->iterations;
89 }
90
91
92 static void
93 rorschach_draw_step (Display *dpy, Window window, struct state *st)
94 {
95 # define ITER_CHUNK 300
96   XPoint points [4 * ITER_CHUNK];
97   int x = st->current_x;
98   int y = st->current_y;
99   int i, j = 0;
100
101   int this_iterations = ITER_CHUNK;
102   if (this_iterations > st->remaining_iterations)
103     this_iterations = st->remaining_iterations;
104
105   for (i = 0; i < this_iterations; i++)
106     {
107       x += ((random () % (1 + (st->offset << 1))) - st->offset);
108       y += ((random () % (1 + (st->offset << 1))) - st->offset);
109       points [j].x = x;
110       points [j].y = y;
111       j++;
112       if (st->xsym)
113         {
114           points [j].x = st->xlim - x;
115           points [j].y = y;
116           j++;
117         }
118       if (st->ysym)
119         {
120           points [j].x = x;
121           points [j].y = st->ylim - y;
122           j++;
123         }
124       if (st->xsym && st->ysym)
125         {
126           points [j].x = st->xlim - x;
127           points [j].y = st->ylim - y;
128           j++;
129         }
130     }
131   XDrawPoints (dpy, window, st->draw_gc, points, j, CoordModeOrigin);
132   st->remaining_iterations -= this_iterations;
133   if (st->remaining_iterations < 0) st->remaining_iterations = 0;
134   st->current_x = x;
135   st->current_y = y;
136 }
137
138
139 static unsigned long
140 rorschach_draw (Display *dpy, Window window, void *closure)
141 {
142   struct state *st = (struct state *) closure;
143   unsigned long delay = 20000;
144
145   if (st->eraser) {
146     st->eraser = erase_window (dpy, window, st->eraser);
147     goto END;
148   }
149
150   if (st->remaining_iterations > 0)
151     {
152       rorschach_draw_step (dpy, window, st);
153       if (st->remaining_iterations == 0)
154         delay = st->sleep_time * 1000000;
155     }
156   else
157     {
158       if (st->remaining_iterations == 0)
159         st->eraser = erase_window (dpy, window, st->eraser);
160
161       rorschach_draw_start (dpy, window, st);
162     }
163  END:
164   return delay;
165 }
166
167
168 static Bool
169 rorschach_event (Display *dpy, Window window, void *closure, XEvent *event)
170 {
171   return False;
172 }
173
174 static void
175 rorschach_free (Display *dpy, Window window, void *closure)
176 {
177   struct state *st = (struct state *) closure;
178   free (st);
179 }
180
181 \f
182 static const char *rorschach_defaults [] = {
183   ".background: black",
184   ".foreground: white",
185   "*fpsSolid:   true",
186   "*xsymmetry:  true",
187   "*ysymmetry:  false",
188   "*iterations: 4000",
189   "*offset:     7",
190   "*delay:      5",
191   0
192 };
193
194 static XrmOptionDescRec rorschach_options [] = {
195   { "-iterations",      ".iterations",  XrmoptionSepArg, 0 },
196   { "-offset",          ".offset",      XrmoptionSepArg, 0 },
197   { "-xsymmetry",       ".xsymmetry",   XrmoptionNoArg, "true" },
198   { "-ysymmetry",       ".ysymmetry",   XrmoptionNoArg, "true" },
199   { "-no-xsymmetry",    ".xsymmetry",   XrmoptionNoArg, "false" },
200   { "-no-ysymmetry",    ".ysymmetry",   XrmoptionNoArg, "false" },
201   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
202   { 0, 0, 0, 0 }
203 };
204
205 XSCREENSAVER_MODULE ("Rorschach", rorschach)