http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / glx / xpm-ximage.c
1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2  * xscreensaver, Copyright (c) 1998, 2001, 2002 Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  * Alpha channel support by Eric Lassauge <lassauge@mail.dotcom.fr>.
13  */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #include <stdlib.h>
20 #include <stdio.h>
21
22 extern char *progname;
23
24
25 #if defined(HAVE_GDK_PIXBUF)
26
27 # include <gdk-pixbuf/gdk-pixbuf.h>
28 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
29
30
31 /* Returns an XImage structure containing the bits of the given XPM image.
32    This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
33    extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
34
35    The Display and Visual arguments are used only for creating the XImage;
36    no bits are pushed to the server.
37
38    The Colormap argument is used just for parsing color names; no colors
39    are allocated.
40
41    This is the gdk_pixbuf version of this function.
42  */
43 static XImage *
44 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
45                  const char *filename,
46                  char **xpm_data)
47 {
48   GdkPixbuf *pb;
49   static int initted = 0;
50
51   if (!initted)
52     {
53       gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
54       xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
55       initted = 1;
56     }
57
58   pb = (filename
59         ? gdk_pixbuf_new_from_file (filename)
60         : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
61   if (pb)
62     {
63       XImage *image;
64       int w = gdk_pixbuf_get_width (pb);
65       int h = gdk_pixbuf_get_height (pb);
66       guchar *row = gdk_pixbuf_get_pixels (pb);
67       int stride = gdk_pixbuf_get_rowstride (pb);
68       int chan = gdk_pixbuf_get_n_channels (pb);
69       int x, y;
70
71       image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
72       image->data = (char *) malloc(h * image->bytes_per_line);
73       if (!image->data)
74         {
75           fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
76           exit (1);
77         }
78
79       for (y = 0; y < h; y++)
80         {
81           int y2 = (h-1-y); /* Texture maps are upside down. */
82
83           guchar *i = row;
84           for (x = 0; x < w; x++)
85             {
86               unsigned long rgba = 0;
87               switch (chan) {
88               case 1:
89                 rgba = ((0xFF << 24) |
90                         (*i << 16) |
91                         (*i << 8) |
92                          *i);
93                 i++;
94                 break;
95               case 3:
96                 rgba = ((0xFF << 24) |
97                         (i[2] << 16) |
98                         (i[1] << 8) |
99                          i[0]);
100                 i += 3;
101                 break;
102               case 4:
103                 rgba = ((i[3] << 24) |
104                         (i[2] << 16) |
105                         (i[1] << 8) |
106                          i[0]);
107                 i += 4;
108                 break;
109               default:
110                 abort();
111                 break;
112               }
113               XPutPixel (image, x, y2, rgba);
114             }
115           row += stride;
116         }
117       /* gdk_pixbuf_unref (pb);  -- #### does doing this free colors? */
118
119       return image;
120     }
121   else if (filename)
122     {
123       fprintf (stderr, "%s: unable to load %s\n", progname, filename);
124       exit (1);
125     }
126   else
127     {
128       fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
129       exit (1);
130     }
131 }
132
133
134 #elif defined(HAVE_XPM)
135
136
137 #include <stdlib.h>
138 #include <stdio.h>
139 #include <X11/Intrinsic.h>
140
141 #include <X11/Xutil.h>
142 #include <X11/xpm.h>
143
144 #undef countof
145 #define countof(x) (sizeof((x))/sizeof((*x)))
146
147 static Bool
148 bigendian (void)
149 {
150   union { int i; char c[sizeof(int)]; } u;
151   u.i = 1;
152   return !u.c[0];
153 }
154
155
156 /* The libxpm version of this function...
157  */
158 static XImage *
159 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
160                  const char *filename, char **xpm_data)
161 {
162   /* All we want to do is get RGB data out of the XPM file built in to this
163      program.  This is a pain, because there is no way  (as of XPM version
164      4.6, at least) to get libXpm to make an XImage without also allocating
165      colors with XAllocColor.  So, instead, we create an XpmImage and parse
166      out the RGB values of the pixels ourselves; and construct an XImage
167      by hand.  Regardless of the depth of the visual we're using, this
168      XImage will have 32 bits per pixel, 8 each per R, G, and B.  We put
169      0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
170    */
171   XImage *ximage = 0;
172   XpmImage xpm_image;
173   XpmInfo xpm_info;
174   int result;
175   int transparent_color_index = -1;
176   int x, y, i;
177   int bpl, wpl;
178   XColor colors[256];
179
180   memset (&xpm_image, 0, sizeof(xpm_image));
181   memset (&xpm_info, 0, sizeof(xpm_info));
182
183   if (filename)
184     {
185       xpm_data = 0;
186       if (! XpmReadFileToData ((char *) filename, &xpm_data))
187         {
188           fprintf (stderr, "%s: unable to read XPM file %f\n",
189                    progname, filename);
190           exit (1);
191         }
192     }
193
194   result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
195   if (result != XpmSuccess)
196     {
197       fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
198               result);
199       exit (1);
200     }
201
202   if (xpm_image.ncolors > countof(colors))
203     {
204       fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
205                progname, xpm_image.ncolors);
206       exit (1);
207     }
208
209   ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
210                          xpm_image.width, xpm_image.height, 32, 0);
211
212   bpl = ximage->bytes_per_line;
213   wpl = bpl/4;
214
215   ximage->data = (char *) malloc(xpm_image.height * bpl);
216
217   /* Parse the colors in the XPM into RGB values. */
218   for (i = 0; i < xpm_image.ncolors; i++)
219     {
220       const char *c = xpm_image.colorTable[i].c_color;
221       if (!c)
222         {
223           fprintf(stderr, "%s: bogus color table?  ($d)\n", progname, i);
224           exit (1);
225         }
226       else if (!strncasecmp (c, "None", 4))
227         {
228           transparent_color_index = i;
229           colors[transparent_color_index].red   = 0xFF;
230           colors[transparent_color_index].green = 0xFF;
231           colors[transparent_color_index].blue  = 0xFF;
232         }
233       else if (!XParseColor (dpy, cmap, c, &colors[i]))
234         {
235           fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
236           exit (1);
237         }
238     }
239
240   /* Translate the XpmImage to an RGB XImage. */
241   {
242     int rpos, gpos, bpos, apos;  /* bitfield positions */
243
244     /* Note that unlike X, which is endianness-agnostic (since any XImage
245        can have its own specific bit ordering, with the server reversing
246        things as necessary) OpenGL pretends everything is client-side, so
247        we need to pack things in the right order for the client machine.
248      */
249     if (bigendian())
250       rpos = 24, gpos = 16, bpos =  8, apos =  0;
251     else
252       rpos =  0, gpos =  8, bpos = 16, apos = 24;
253
254     for (y = 0; y < xpm_image.height; y++)
255       {
256         int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
257
258         unsigned int *oline = (unsigned int *) (ximage->data   + (y  * bpl));
259         unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
260
261         for (x = 0; x < xpm_image.width; x++)
262           {
263             XColor *c = &colors[iline[x]];
264             int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
265             oline[x] = (((c->red   >> 8) << rpos) |
266                         ((c->green >> 8) << gpos) |
267                         ((c->blue  >> 8) << bpos) |
268                         (alpha           << apos));
269           }
270       }
271   }
272
273   /* I sure hope these only free the contents, and not the args. */
274 #if 0  /* Apparently not?  Gotta love those well-documented APIs! */
275   XpmFreeXpmImage (&xpm_image);
276   XpmFreeXpmInfo (&xpm_info);
277 #endif
278
279   return ximage;
280 }
281
282
283 #else  /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
284
285 static XImage *
286 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
287                  const char *filename, char **xpm_data)
288 {
289   fprintf(stderr, "%s: not compiled with XPM or Pixbuf support.\n", progname);
290   exit (1);
291 }
292
293 #endif /* !HAVE_XPM */
294
295
296 /* Returns an XImage structure containing the bits of the given XPM image.
297    This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
298    extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
299
300    The Display and Visual arguments are used only for creating the XImage;
301    no bits are pushed to the server.
302
303    The Colormap argument is used just for parsing color names; no colors
304    are allocated.
305  */
306 XImage *
307 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
308 {
309   return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
310 }
311
312
313 XImage *
314 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
315                     const char *filename)
316 {
317   return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);
318 }