began for maemo
[xscreensaver] / xscreensaver / hacks / blitspin.c
1 /* xscreensaver, Copyright (c) 1992-2006 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
12 /* Rotate a bitmap using using bitblts.
13    The bitmap must be square, and must be a power of 2 in size.
14    This was translated from SmallTalk code which appeared in the
15    August 1981 issue of Byte magazine.
16
17    The input bitmap may be non-square, it is padded and centered
18    with the background color.  Another way would be to subdivide
19    the bitmap into square components and rotate them independently
20    (and preferably in parallel), but I don't think that would be as
21    interesting looking.
22
23    It's too bad almost nothing uses blitter hardware these days,
24    or this might actually win.
25  */
26
27 #include "screenhack.h"
28 #include "xpm-pixmap.h"
29 #include <stdio.h>
30
31 #include "images/som.xbm"
32
33 struct state {
34   Display *dpy;
35   Window window;
36   XWindowAttributes xgwa;
37   int width, height, size;
38   Bool scale_up;
39   Pixmap self, temp, mask;
40   GC SET, CLR, CPY, IOR, AND, XOR;
41   GC gc;
42   int delay, delay2;
43   Pixmap bitmap;
44   unsigned int fg, bg;
45
46   int qwad; /* fuckin' C, man... who needs namespaces? */
47   int first_time;
48   int last_w, last_h;
49
50   Bool loaded_p;
51   async_load_state *img_loader;
52 };
53
54 static void display (struct state *, Pixmap);
55 static void blitspin_init_2 (struct state *);
56
57 #define copy_all_to(from, xoff, yoff, to, gc)                   \
58   XCopyArea (st->dpy, (from), (to), (gc), 0, 0,                 \
59              st->size-(xoff), st->size-(yoff), (xoff), (yoff))
60
61 #define copy_all_from(to, xoff, yoff, from, gc)                 \
62   XCopyArea (st->dpy, (from), (to), (gc), (xoff), (yoff),       \
63              st->size-(xoff), st->size-(yoff), 0, 0)
64
65 static unsigned long
66 blitspin_draw (Display *dpy, Window window, void *closure)
67 {
68   struct state *st = (struct state *) closure;
69   int this_delay = st->delay;
70
71   if (st->img_loader)   /* still loading */
72     {
73       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
74       return this_delay;
75     }
76
77   if (! st->loaded_p) {
78     blitspin_init_2 (st);
79     st->loaded_p = True;
80   }
81
82   if (st->qwad == -1) 
83     {
84       XFillRectangle (st->dpy, st->mask, st->CLR, 0, 0, st->size, st->size);
85       XFillRectangle (st->dpy, st->mask, st->SET, 0, 0, st->size>>1, st->size>>1);
86       st->qwad = st->size>>1;
87     }
88
89   if (st->first_time)
90     {
91       st->first_time = 0;
92       display (st, st->self);
93       return st->delay2;
94     }
95
96   /* for (st->qwad = st->size>>1; st->qwad > 0; st->qwad>>=1) */
97
98   copy_all_to   (st->mask,       0,       0, st->temp, st->CPY);  /* 1 */
99   copy_all_to   (st->mask,       0,    st->qwad, st->temp, st->IOR);  /* 2 */
100   copy_all_to   (st->self,       0,       0, st->temp, st->AND);  /* 3 */
101   copy_all_to   (st->temp,       0,       0, st->self, st->XOR);  /* 4 */
102   copy_all_from (st->temp,    st->qwad,       0, st->self, st->XOR);  /* 5 */
103   copy_all_from (st->self,    st->qwad,       0, st->self, st->IOR);  /* 6 */
104   copy_all_to   (st->temp,    st->qwad,       0, st->self, st->XOR);  /* 7 */
105   copy_all_to   (st->self,       0,       0, st->temp, st->CPY);  /* 8 */
106   copy_all_from (st->temp,    st->qwad,    st->qwad, st->self, st->XOR);  /* 9 */
107   copy_all_to   (st->mask,       0,       0, st->temp, st->AND);  /* A */
108   copy_all_to   (st->temp,       0,       0, st->self, st->XOR);  /* B */
109   copy_all_to   (st->temp,    st->qwad,    st->qwad, st->self, st->XOR);  /* C */
110   copy_all_from (st->mask, st->qwad>>1, st->qwad>>1, st->mask, st->AND);  /* D */
111   copy_all_to   (st->mask,    st->qwad,       0, st->mask, st->IOR);  /* E */
112   copy_all_to   (st->mask,       0,    st->qwad, st->mask, st->IOR);  /* F */
113   display (st, st->self);
114
115   st->qwad >>= 1;
116   if (st->qwad == 0)  /* done with this round */
117     {
118       st->qwad = -1;
119       this_delay = st->delay2;
120     }
121
122   return this_delay;
123 }
124
125
126 static int 
127 to_pow2(struct state *st, int n, Bool up)
128 {
129   /* sizeof(Dimension) == 2. */
130   int powers_of_2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
131                         2048, 4096, 8192, 16384, 32768, 65536 };
132   int i = 0;
133   if (n > 65536) st->size = 65536;
134   while (n >= powers_of_2[i]) i++;
135   if (n == powers_of_2[i-1])
136     return n;
137   else
138     return powers_of_2[up ? i : i-1];
139 }
140
141 static void *
142 blitspin_init (Display *d_arg, Window w_arg)
143 {
144   struct state *st = (struct state *) calloc (1, sizeof(*st));
145   char *bitmap_name;
146
147   st->dpy = d_arg;
148   st->window = w_arg;
149
150   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
151
152   st->fg = get_pixel_resource (st->dpy, st->xgwa.colormap,
153                                "foreground", "Foreground");
154   st->bg = get_pixel_resource (st->dpy, st->xgwa.colormap,
155                                "background", "Background");
156   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
157   st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
158   if (st->delay < 0) st->delay = 0;
159   if (st->delay2 < 0) st->delay2 = 0;
160   bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
161   if (! bitmap_name || !*bitmap_name)
162     bitmap_name = "(default)";
163
164   if (!strcasecmp (bitmap_name, "(default)") ||
165       !strcasecmp (bitmap_name, "default"))
166 # ifdef HAVE_COCOA
167     bitmap_name = "(builtin)";
168 # else
169     bitmap_name = "(screen)";
170 # endif
171
172   if (!strcasecmp (bitmap_name, "(builtin)") ||
173       !strcasecmp (bitmap_name, "builtin"))
174     {
175       st->width = som_width;
176       st->height = som_height;
177       st->bitmap = XCreatePixmapFromBitmapData (st->dpy, st->window,
178                                                 (char *) som_bits,
179                                                 st->width, st->height, 
180                                                 st->fg, st->bg, 
181                                                 st->xgwa.depth);
182       st->scale_up = True; /* definitely. */
183     }
184   else if (!strcasecmp (bitmap_name, "(screen)") ||
185            !strcasecmp (bitmap_name, "screen"))
186     {
187       st->bitmap = XCreatePixmap (st->dpy, st->window, 
188                                   st->xgwa.width, st->xgwa.height,
189                                   st->xgwa.depth);
190       st->width = st->xgwa.width;
191       st->height = st->xgwa.height;
192       st->scale_up = True; /* maybe? */
193       st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
194                                             st->bitmap, 0, 0);
195     }
196   else
197     {
198       st->bitmap = xpm_file_to_pixmap (st->dpy, st->window, bitmap_name,
199                                    &st->width, &st->height, 0);
200       st->scale_up = True; /* probably? */
201     }
202
203   return st;
204 }
205
206
207 static void
208 blitspin_init_2 (struct state *st)
209 {
210   XGCValues gcv;
211
212   /* make it square */
213   st->size = (st->width < st->height) ? st->height : st->width;
214   st->size = to_pow2(st, st->size, st->scale_up); /* round up to power of 2 */
215   {                                             /* don't exceed screen size */
216     int s = XScreenNumberOfScreen(st->xgwa.screen);
217     int w = to_pow2(st, XDisplayWidth(st->dpy, s), False);
218     int h = to_pow2(st, XDisplayHeight(st->dpy, s), False);
219     if (st->size > w) st->size = w;
220     if (st->size > h) st->size = h;
221   }
222
223   st->self = XCreatePixmap (st->dpy, st->window, st->size, st->size, st->xgwa.depth);
224   st->temp = XCreatePixmap (st->dpy, st->window, st->size, st->size, st->xgwa.depth);
225   st->mask = XCreatePixmap (st->dpy, st->window, st->size, st->size, st->xgwa.depth);
226   gcv.foreground = (st->xgwa.depth == 1 ? 1 : (~0));
227   gcv.function=GXset;  st->SET = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
228   gcv.function=GXclear;st->CLR = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
229   gcv.function=GXcopy; st->CPY = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
230   gcv.function=GXor;   st->IOR = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
231   gcv.function=GXand;  st->AND = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
232   gcv.function=GXxor;  st->XOR = XCreateGC(st->dpy,st->self,GCFunction|GCForeground,&gcv);
233
234   gcv.foreground = gcv.background = st->bg;
235   st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv);
236   /* Clear st->self to the background color (not to 0, which st->CLR does.) */
237   XFillRectangle (st->dpy, st->self, st->gc, 0, 0, st->size, st->size);
238   XSetForeground (st->dpy, st->gc, st->fg);
239
240   XCopyArea (st->dpy, st->bitmap, st->self, st->CPY, 0, 0, 
241              st->width, st->height,
242              (st->size - st->width)  >> 1,
243              (st->size - st->height) >> 1);
244   XFreePixmap(st->dpy, st->bitmap);
245
246   st->qwad = -1;
247   st->first_time = 1;
248 }
249
250 static void
251 display (struct state *st, Pixmap pixmap)
252 {
253   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
254
255   if (st->xgwa.width != st->last_w || 
256       st->xgwa.height != st->last_h)
257     {
258       XClearWindow (st->dpy, st->window);
259       st->last_w = st->xgwa.width;
260       st->last_h = st->xgwa.height;
261     }
262   if (st->xgwa.depth != 1)
263     XCopyArea (st->dpy, pixmap, st->window, st->gc, 0, 0, st->size, st->size,
264                (st->xgwa.width - st->size) >> 1,
265                (st->xgwa.height - st->size) >> 1);
266   else
267     XCopyPlane (st->dpy, pixmap, st->window, st->gc, 0, 0, st->size, st->size,
268                 (st->xgwa.width - st->size) >> 1,
269                 (st->xgwa.height - st->size) >> 1,
270                 1);
271 /*
272   XDrawRectangle (st->dpy, st->window, st->gc,
273                   ((st->xgwa.width - st->size) >> 1) - 1,
274                   ((st->xgwa.height - st->size) >> 1) - 1,
275                   st->size+2, st->size+2);
276 */
277 }
278
279 static void
280 blitspin_reshape (Display *dpy, Window window, void *closure, 
281                   unsigned int w, unsigned int h)
282 {
283 }
284
285 static Bool
286 blitspin_event (Display *dpy, Window window, void *closure, XEvent *event)
287 {
288   return False;
289 }
290
291 static void
292 blitspin_free (Display *dpy, Window window, void *closure)
293 {
294 }
295
296 \f
297 static const char *blitspin_defaults [] = {
298   ".background: black",
299   ".foreground: white",
300   "*delay:      500000",
301   "*delay2:     500000",
302   "*bitmap:     (default)",
303   "*geometry:   512x512",
304   0
305 };
306
307 static XrmOptionDescRec blitspin_options [] = {
308   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
309   { "-delay2",          ".delay2",      XrmoptionSepArg, 0 },
310   { "-bitmap",          ".bitmap",      XrmoptionSepArg, 0 },
311   { 0, 0, 0, 0 }
312 };
313
314
315 XSCREENSAVER_MODULE ("BlitSpin", blitspin)