From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / moire.c
1 /* xscreensaver, Copyright (c) 1997-2013 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  * Concept snarfed from Michael D. Bayne in
12  * http://samskivert.com/internet/deep/1997/04/16/body.html
13  */
14
15 #include "screenhack.h"
16 #include "xshm.h"
17
18 struct state {
19   Display *dpy;
20   Window window;
21   XShmSegmentInfo shm_info;
22
23   int delay;
24   int offset;
25   XColor *colors;
26   int ncolors;
27   GC gc;
28   unsigned long fg_pixel;
29   unsigned long bg_pixel;
30   int depth;
31
32   int draw_y, draw_xo, draw_yo;
33   int draw_factor;
34   XImage *draw_image;
35   XWindowAttributes xgwa;
36 };
37
38 static void
39 moire_init_1 (struct state *st)
40 {
41   int oncolors;
42   int i;
43   int fgh, bgh;
44   double fgs, fgv, bgs, bgv;
45   XWindowAttributes xgwa;
46   XColor fgc, bgc;
47   XGCValues gcv;
48
49   XGetWindowAttributes (st->dpy, st->window, &xgwa);
50
51   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
52   st->offset = get_integer_resource (st->dpy, "offset", "Integer");
53   if (st->offset < 2) st->offset = 2;
54
55  MONO:
56   if (st->colors)
57     {
58       for (i = 0; i < st->ncolors; i++)
59         XFreeColors (st->dpy, xgwa.colormap, &st->colors[i].pixel, 1, 0);
60       free(st->colors);
61       st->colors = 0;
62     }
63
64   if (mono_p)
65     {
66       st->fg_pixel = WhitePixelOfScreen (DefaultScreenOfDisplay(st->dpy));
67       st->bg_pixel = BlackPixelOfScreen (DefaultScreenOfDisplay(st->dpy));
68     }
69   else
70     {
71       st->fg_pixel = get_pixel_resource (st->dpy,
72                                      xgwa.colormap, "foreground", "Foreground");
73       st->bg_pixel = get_pixel_resource (st->dpy,
74                                      xgwa.colormap, "background", "Background");
75     }
76
77   if (mono_p)
78     {
79       st->offset *= 20;   /* compensate for lack of shading */
80       gcv.foreground = st->fg_pixel;
81     }
82   else
83     {
84       st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
85       if (st->ncolors < 2) st->ncolors = 2;
86       oncolors = st->ncolors;
87
88       fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue;
89       if (get_boolean_resource(st->dpy, "random","Boolean"))
90         {
91           fgc.red   = random() & 0xFFFF;
92           fgc.green = random() & 0xFFFF;
93           fgc.blue  = random() & 0xFFFF;
94           bgc.red   = random() & 0xFFFF;
95           bgc.green = random() & 0xFFFF;
96           bgc.blue  = random() & 0xFFFF;
97         }
98       else
99         {
100           fgc.pixel = st->fg_pixel;
101           bgc.pixel = st->bg_pixel;
102           XQueryColor (st->dpy, xgwa.colormap, &fgc);
103           XQueryColor (st->dpy, xgwa.colormap, &bgc);
104         }
105       rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
106       rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
107
108       st->colors = (XColor *) malloc (sizeof (XColor) * (st->ncolors+2));
109       memset(st->colors, 0, (sizeof (XColor) * (st->ncolors+2)));
110       make_color_ramp (xgwa.screen, xgwa.visual, xgwa.colormap,
111                        fgh, fgs, fgv, bgh, bgs, bgv,
112                        st->colors, &st->ncolors,
113                        True, True, False);
114       if (st->ncolors != oncolors)
115         fprintf(stderr, "%s: got %d of %d requested colors.\n",
116                 progname, st->ncolors, oncolors);
117
118       if (st->ncolors <= 2)
119         {
120           mono_p = True;
121           goto MONO;
122         }
123
124       gcv.foreground = st->colors[0].pixel;
125     }
126   st->gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
127 }
128
129
130 static void *
131 moire_init (Display *dpy, Window window)
132 {
133   struct state *st = (struct state *) calloc (1, sizeof(*st));
134   st->dpy = dpy;
135   st->window = window;
136   moire_init_1 (st);
137   return st;
138 }
139
140
141 static unsigned long
142 moire_draw (Display *dpy, Window window, void *closure)
143 {
144   struct state *st = (struct state *) closure;
145   XGCValues gcv;
146   int chunk_size = 20, ii;
147
148   if (st->draw_y == 0) 
149     {
150       moire_init_1 (st);
151
152       XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
153
154       st->draw_xo = (random() % st->xgwa.width)  - st->xgwa.width/2;
155       st->draw_yo = (random() % st->xgwa.height) - st->xgwa.height/2;
156       st->draw_factor = (random() % st->offset) + 1;
157
158       st->depth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
159
160       st->draw_image = create_xshm_image(st->dpy, st->xgwa.visual,
161                                          st->depth, ZPixmap, &st->shm_info, /* depth, format, shm_info */
162                                          st->xgwa.width, chunk_size);       /* w, h */
163     }
164
165   /* for (y = 0; y < st->xgwa.height; y++) */
166   for (ii = 0; ii < chunk_size; ii++)
167     {
168       int x;
169       for (x = 0; x < st->xgwa.width; x++)
170         {
171           double xx = x + st->draw_xo;
172           double yy = st->draw_y + ii + st->draw_yo;
173           double i = ((xx * xx) + (yy * yy)) / (double) st->draw_factor;
174           if (mono_p)
175             gcv.foreground = ((((long) i) & 1) ? st->fg_pixel : st->bg_pixel);
176           else
177             gcv.foreground = st->colors[((long) i) % st->ncolors].pixel;
178           XPutPixel (st->draw_image, x, ii, gcv.foreground);
179         }
180
181       if (st->draw_y + ii >= st->xgwa.height)
182         break;
183     }
184
185     put_xshm_image(st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, chunk_size, &st->shm_info);
186     st->draw_y += chunk_size;
187
188     if (st->draw_y >= st->xgwa.height)
189       {
190         st->draw_y = 0;
191
192         destroy_xshm_image (st->dpy, st->draw_image, &st->shm_info);
193         st->draw_image = 0;
194
195         return st->delay * 1000000;
196       }
197
198   return st->delay * 10000;
199 }
200
201 \f
202 static const char *moire_defaults [] = {
203   ".background:         blue",
204   ".foreground:         red",
205   "*fpsSolid:           true",
206   "*random:             true",
207   "*delay:              5",
208   "*ncolors:            64",
209   "*offset:             50",
210   "*useSHM:           True",
211 #ifdef HAVE_MOBILE
212   "*ignoreRotation: True",
213 #endif
214   0
215 };
216
217 static XrmOptionDescRec moire_options [] = {
218   { "-random",          ".random",      XrmoptionNoArg, "True" },
219   { "-no-random",       ".random",      XrmoptionNoArg, "False" },
220   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
221   { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
222   { "-offset",          ".offset",      XrmoptionSepArg, 0 },
223   { "-shm",             ".useSHM",      XrmoptionNoArg, "True" },
224   { "-no-shm",          ".useSHM",      XrmoptionNoArg, "False" },
225   { 0, 0, 0, 0 }
226 };
227
228 static void
229 moire_reshape (Display *dpy, Window window, void *closure, 
230                  unsigned int w, unsigned int h)
231 {
232 }
233
234 static Bool
235 moire_event (Display *dpy, Window window, void *closure, XEvent *event)
236 {
237   return False;
238 }
239
240 static void
241 moire_free (Display *dpy, Window window, void *closure)
242 {
243 }
244
245 XSCREENSAVER_MODULE ("Moire", moire)