912ccc705628ec4e81895da0107f931dedf7e3bd
[xscreensaver] / hacks / cwaves.c
1 /* xscreensaver, Copyright (c) 2007 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  * cwaves -- languid sinusoidal colors.
12  */
13
14 #include "screenhack.h"
15 #include <stdio.h>
16 #include "xpm-pixmap.h"
17
18 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
19
20 typedef struct {
21   double scale;
22   double offset;
23   double delta;
24 } wave;
25
26 typedef struct {
27   Display *dpy;
28   Window window;
29   XWindowAttributes xgwa;
30   GC gc;
31   int delay;
32   int scale;
33   int ncolors;
34   XColor *colors;
35
36   int nwaves;
37   wave *waves;
38   int debug_p;
39
40 } state;
41
42
43 static void *
44 cwaves_init (Display *dpy, Window window)
45 {
46   int i;
47   XGCValues gcv;
48   state *st = (state *) calloc (1, sizeof (*st));
49
50   st->dpy = dpy;
51   st->window = window;
52   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
53
54   st->debug_p = get_boolean_resource (dpy, "debug", "Boolean");
55   st->scale = get_integer_resource (dpy, "scale", "Integer");
56   if (st->scale <= 0) st->scale = 1;
57   st->ncolors = get_integer_resource (dpy, "ncolors", "Integer");
58   if (st->ncolors < 4) st->ncolors = 4;
59   st->colors = (XColor *) malloc (sizeof(*st->colors) * (st->ncolors+1));
60   make_smooth_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
61                         st->colors, &st->ncolors,
62                         True, 0, False);
63
64   st->gc = XCreateGC (st->dpy, st->window, 0, &gcv);
65   st->delay = get_integer_resource (dpy, "delay", "Integer");
66
67   st->nwaves  = get_integer_resource (dpy, "nwaves", "Integer");
68   st->waves  = (wave *) calloc (st->nwaves,  sizeof(*st->waves));
69
70   for (i = 0; i < st->nwaves; i++)
71     {
72       st->waves[i].scale  = frand(0.03) + 0.005;
73       st->waves[i].offset = frand(M_PI);
74       st->waves[i].delta  = (BELLRAND(2)-1) / 15.0;
75     }
76
77   return st;
78 }
79
80
81 static unsigned long
82 cwaves_draw (Display *dpy, Window window, void *closure)
83 {
84   state *st = (state *) closure;
85   int i, x;
86
87   for (i = 0; i < st->nwaves; i++)
88     st->waves[i].offset += st->waves[i].delta;
89
90   for (x = 0; x < st->xgwa.width; x += st->scale)
91     {
92       double v = 0;
93       int j;
94       for (i = 0; i < st->nwaves; i++)
95         v += cos ((x * st->waves[i].scale) - st->waves[i].offset);
96       v /= st->nwaves;
97
98       j = st->ncolors * (v/2 + 0.5);
99       if (j < 0 || j >= st->ncolors) abort();
100       XSetForeground (st->dpy, st->gc, st->colors[j].pixel);
101       XFillRectangle (st->dpy, st->window, st->gc, 
102                       x, 0, st->scale, st->xgwa.height);
103     }
104
105   if (st->debug_p)
106     {
107       int wh = (st->xgwa.height / (st->nwaves + 1)) * 0.9;
108       int i;
109       XSetLineAttributes (st->dpy, st->gc, 2, LineSolid, CapRound, JoinRound);
110       XSetForeground (st->dpy, st->gc, BlackPixelOfScreen (st->xgwa.screen));
111       for (i = 0; i < st->nwaves; i++)
112         {
113           int y = st->xgwa.height * i / (st->nwaves + 1);
114           int ox = -1, oy = -1;
115
116           for (x = 0; x < st->xgwa.width; x += st->scale)
117             {
118               int yy;
119               double v = 0;
120               v = cos ((x * st->waves[i].scale) - st->waves[i].offset);
121               v /= 2;
122
123               yy = y + wh/2 + (wh * v);
124               if (ox == -1)
125                 ox = x, oy = yy;
126               XDrawLine (st->dpy, st->window, st->gc, ox, oy, x, yy);
127               ox = x;
128               oy = yy;
129             }
130         }
131
132       {
133         int y = st->xgwa.height * i / (st->nwaves + 1);
134         int ox = -1, oy = -1;
135
136         for (x = 0; x < st->xgwa.width; x += st->scale)
137           {
138             int yy;
139             double v = 0;
140             for (i = 0; i < st->nwaves; i++)
141               v += cos ((x * st->waves[i].scale) - st->waves[i].offset);
142             v /= st->nwaves;
143             v /= 2;
144
145             yy = y + wh/2 + (wh * v);
146             if (ox == -1)
147               ox = x, oy = yy;
148             XDrawLine (st->dpy, st->window, st->gc, ox, oy, x, yy);
149             ox = x;
150             oy = yy;
151           }
152       }
153     }
154
155   return st->delay;
156 }
157
158
159 static void
160 cwaves_reshape (Display *dpy, Window window, void *closure, 
161                  unsigned int w, unsigned int h)
162 {
163   state *st = (state *) closure;
164   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
165 }
166
167 static Bool
168 cwaves_event (Display *dpy, Window window, void *closure, XEvent *event)
169 {
170   state *st = (state *) closure;
171   if (event->type == ButtonPress)
172     {
173       make_smooth_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
174                             st->colors, &st->ncolors,
175                             True, 0, False);
176       return True;
177     }
178   return False;
179 }
180
181 static void
182 cwaves_free (Display *dpy, Window window, void *closure)
183 {
184 }
185
186
187 static const char *cwaves_defaults [] = {
188   ".background:            black",
189   ".foreground:            white",
190   "*ncolors:               600",
191   "*nwaves:                15",
192   "*scale:                 2",
193   "*debug:                 False",
194   "*delay:                 20000",
195   0
196 };
197
198 static XrmOptionDescRec cwaves_options [] = {
199   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
200   { "-waves",           ".nwaves",              XrmoptionSepArg, 0 },
201   { "-colors",          ".ncolors",             XrmoptionSepArg, 0 },
202   { "-scale",           ".scale",               XrmoptionSepArg, 0 },
203   { "-debug",           ".debug",               XrmoptionNoArg, "True" },
204   { 0, 0, 0, 0 }
205 };
206
207
208 XSCREENSAVER_MODULE ("CWaves", cwaves)