ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.27.tar.Z
[xscreensaver] / hacks / blitspin.c
1 /* xscreensaver, Copyright (c) 1992-1996 Jamie Zawinski <jwz@netscape.com>
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 <stdio.h>
29
30 #ifdef HAVE_XPM
31 # include <X11/xpm.h>
32 # ifndef PIXEL_ALREADY_TYPEDEFED
33 #  define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
34 # endif
35 #endif
36
37 #include <X11/Xmu/Drawing.h>
38
39 #include "default.xbm"
40
41 static Display *dpy;
42 static Window window;
43 static unsigned int size;
44 static Pixmap self, temp, mask;
45 static GC SET, CLR, CPY, IOR, AND, XOR;
46 static GC gc;
47 static int delay, delay2;
48 static Pixmap bitmap;
49 static int depth;
50 static unsigned int fg, bg;
51
52 static void rotate(), init (), display ();
53
54 #define copy_all_to(from, xoff, yoff, to, gc)           \
55   XCopyArea (dpy, (from), (to), (gc), 0, 0,             \
56              size-(xoff), size-(yoff), (xoff), (yoff))
57
58 #define copy_all_from(to, xoff, yoff, from, gc)         \
59   XCopyArea (dpy, (from), (to), (gc), (xoff), (yoff),   \
60              size-(xoff), size-(yoff), 0, 0)
61
62 static void
63 rotate ()
64 {
65   int qwad; /* fuckin' C, man... who needs namespaces? */
66   XFillRectangle (dpy, mask, CLR, 0, 0, size, size);
67   XFillRectangle (dpy, mask, SET, 0, 0, size>>1, size>>1);
68   for (qwad = size>>1; qwad > 0; qwad>>=1)
69     {
70       if (delay) usleep (delay);
71       copy_all_to   (mask,       0,       0, temp, CPY);  /* 1 */
72       copy_all_to   (mask,       0,    qwad, temp, IOR);  /* 2 */
73       copy_all_to   (self,       0,       0, temp, AND);  /* 3 */
74       copy_all_to   (temp,       0,       0, self, XOR);  /* 4 */
75       copy_all_from (temp,    qwad,       0, self, XOR);  /* 5 */
76       copy_all_from (self,    qwad,       0, self, IOR);  /* 6 */
77       copy_all_to   (temp,    qwad,       0, self, XOR);  /* 7 */
78       copy_all_to   (self,       0,       0, temp, CPY);  /* 8 */
79       copy_all_from (temp,    qwad,    qwad, self, XOR);  /* 9 */
80       copy_all_to   (mask,       0,       0, temp, AND);  /* A */
81       copy_all_to   (temp,       0,       0, self, XOR);  /* B */
82       copy_all_to   (temp,    qwad,    qwad, self, XOR);  /* C */
83       copy_all_from (mask, qwad>>1, qwad>>1, mask, AND);  /* D */
84       copy_all_to   (mask,    qwad,       0, mask, IOR);  /* E */
85       copy_all_to   (mask,       0,    qwad, mask, IOR);  /* F */
86       display (self);
87     }
88 }
89
90 static void
91 read_bitmap (bitmap_name, widthP, heightP)
92      char *bitmap_name;
93      int *widthP, *heightP;
94 {
95 #ifdef HAVE_XPM
96   XpmAttributes xpmattrs;
97   int result;
98   xpmattrs.valuemask = 0;
99   bitmap = 0;
100
101 #ifdef XpmCloseness
102   xpmattrs.valuemask |= XpmCloseness;
103   xpmattrs.closeness = 40000;
104 #endif
105
106   result = XpmReadFileToPixmap (dpy, window, bitmap_name, &bitmap, 0,
107                                 &xpmattrs);
108   switch (result)
109     {
110     case XpmColorError:
111       fprintf (stderr, "%s: warning: xpm color substitution performed\n",
112                progname);
113       /* fall through */
114     case XpmSuccess:
115       *widthP = xpmattrs.width;
116       *heightP = xpmattrs.height;
117       break;
118     case XpmFileInvalid:
119     case XpmOpenFailed:
120       bitmap = 0;
121       break;
122     case XpmColorFailed:
123       fprintf (stderr, "%s: xpm: color allocation failed\n", progname);
124       exit (-1);
125     case XpmNoMemory:
126       fprintf (stderr, "%s: xpm: out of memory\n", progname);
127       exit (-1);
128     default:
129       fprintf (stderr, "%s: xpm: unknown error code %d\n", progname, result);
130       exit (-1);
131     }
132   if (! bitmap)
133 #endif
134     {
135       int xh, yh;
136       Pixmap b2;
137       bitmap = XmuLocateBitmapFile (DefaultScreenOfDisplay (dpy), bitmap_name,
138                                     0, 0, widthP, heightP, &xh, &yh);
139       if (! bitmap)
140         {
141           fprintf (stderr, "%s: couldn't find bitmap %s\n", progname,
142                    bitmap_name);
143           exit (1);
144         }
145       b2 = XmuCreatePixmapFromBitmap (dpy, window, bitmap, *widthP, *heightP,
146                                       depth, fg, bg);
147       XFreePixmap (dpy, bitmap);
148       bitmap = b2;
149     }
150 }
151
152 static void
153 init ()
154 {
155   XWindowAttributes xgwa;
156   Colormap cmap;
157   XGCValues gcv;
158   int width, height;
159   unsigned int real_size;
160   char *bitmap_name;
161   int i;
162
163   XGetWindowAttributes (dpy, window, &xgwa);
164   cmap = xgwa.colormap;
165   depth = xgwa.depth;
166
167   fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
168   bg = get_pixel_resource ("background", "Background", dpy, cmap);
169   delay = get_integer_resource ("delay", "Integer");
170   delay2 = get_integer_resource ("delay2", "Integer");
171   if (delay < 0) delay = 0;
172   if (delay2 < 0) delay2 = 0;
173   bitmap_name = get_string_resource ("bitmap", "Bitmap");
174   if (! bitmap_name || !*bitmap_name)
175     bitmap_name = "(default)";
176
177   if (!strcmp (bitmap_name, "(default)"))
178     {
179       width = logo_width;
180       height = logo_height;
181       bitmap = XCreatePixmapFromBitmapData (dpy, window, (char *) logo_bits,
182                                             width, height, fg, bg, depth);
183     }
184   else
185     {
186       read_bitmap (bitmap_name, &width, &height);
187     }
188
189   real_size = (width > height) ? width : height;
190
191   size = real_size;
192   /* semi-sleazy way of doing (setq size (expt 2 (ceiling (log size 2)))). */
193   for (i = 31; i > 0; i--)
194     if (size & (1<<i)) break;
195   if (size & (~(1<<i)))
196     size = (size>>i)<<(i+1);
197   self = XCreatePixmap (dpy, window, size, size, depth);
198   temp = XCreatePixmap (dpy, window, size, size, depth);
199   mask = XCreatePixmap (dpy, window, size, size, depth);
200   gcv.foreground = (depth == 1 ? 1 : (~0));
201   gcv.function=GXset;  SET = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
202   gcv.function=GXclear;CLR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
203   gcv.function=GXcopy; CPY = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
204   gcv.function=GXor;   IOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
205   gcv.function=GXand;  AND = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
206   gcv.function=GXxor;  XOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
207
208   gcv.foreground = gcv.background = bg;
209   gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
210   /* Clear self to the background color (not to 0, which CLR does.) */
211   XFillRectangle (dpy, self, gc, 0, 0, size, size);
212   XSetForeground (dpy, gc, fg);
213
214   XCopyArea (dpy, bitmap, self, CPY, 0, 0, width, height,
215              (size - width)>>1, (size - height)>>1);
216 }
217
218 static void
219 display (pixmap)
220      Pixmap pixmap;
221 {
222   XWindowAttributes xgwa;
223   static int last_w = 0, last_h = 0;
224   XGetWindowAttributes (dpy, window, &xgwa);
225   if (xgwa.width != last_w || xgwa.height != last_h)
226     {
227       XClearWindow (dpy, window);
228       last_w = xgwa.width;
229       last_h = xgwa.height;
230     }
231 #ifdef HAVE_XPM
232   if (depth != 1)
233     XCopyArea (dpy, pixmap, window, gc, 0, 0, size, size,
234                (xgwa.width-size)>>1, (xgwa.height-size)>>1);
235   else
236 #endif
237     XCopyPlane (dpy, pixmap, window, gc, 0, 0, size, size,
238                 (xgwa.width-size)>>1, (xgwa.height-size)>>1, 1);
239 /*
240   XDrawRectangle (dpy, window, gc,
241                   ((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1,
242                   size+2, size+2);
243 */
244   XSync (dpy, True);
245 }
246
247 \f
248 char *progclass = "BlitSpin";
249
250 char *defaults [] = {
251   "BlitSpin.background: black",         /* to placate SGI */
252   "BlitSpin.foreground: white",
253   "*delay:      500000",
254   "*delay2:     500000",
255   "*bitmap:     (default)",
256   0
257 };
258
259 XrmOptionDescRec options [] = {
260   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
261   { "-delay2",          ".delay2",      XrmoptionSepArg, 0 },
262   { "-bitmap",          ".bitmap",      XrmoptionSepArg, 0 }
263 };
264 int options_size = (sizeof (options) / sizeof (options[0]));
265
266 void
267 screenhack (d, w)
268      Display *d;
269      Window w;
270 {
271   dpy = d;
272   window = w;
273   init ();
274   while (1)
275     {
276       rotate ();
277       if (delay2) usleep (delay2);
278     }
279 }