http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[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-2006 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@users.sourceforge.net>
13  */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #include <stdlib.h>
20 #include <stdio.h>
21
22 #ifdef HAVE_COCOA
23 # include "jwxyz.h"
24 #else
25 # include <X11/Xlib.h>
26 #endif
27
28 #include "xpm-ximage.h"
29
30 extern char *progname;
31
32
33 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
34 static Bool
35 bigendian (void)
36 {
37   union { int i; char c[sizeof(int)]; } u;
38   u.i = 1;
39   return !u.c[0];
40 }
41 #endif /* HAVE_GDK_PIXBUF || HAVE_XPM */
42
43
44 #if defined(HAVE_GDK_PIXBUF)
45
46 # include <gdk-pixbuf/gdk-pixbuf.h>
47
48 # ifdef HAVE_GTK2
49 #  include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
50 # else  /* !HAVE_GTK2 */
51 #  include <gdk-pixbuf/gdk-pixbuf-xlib.h>
52 # endif /* !HAVE_GTK2 */
53
54
55 /* Returns an XImage structure containing the bits of the given XPM image.
56    This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
57    extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
58
59    The Display and Visual arguments are used only for creating the XImage;
60    no bits are pushed to the server.
61
62    The Colormap argument is used just for parsing color names; no colors
63    are allocated.
64
65    This is the gdk_pixbuf version of this function.
66  */
67 static XImage *
68 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
69                  const char *filename,
70                  char **xpm_data)
71 {
72   GdkPixbuf *pb;
73   static int initted = 0;
74 #ifdef HAVE_GTK2
75   GError *gerr = NULL;
76 #endif
77
78   if (!initted)
79     {
80 #ifdef HAVE_GTK2
81       g_type_init ();
82 #endif
83       gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
84       xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
85       initted = 1;
86     }
87
88   pb = (filename
89 #ifdef HAVE_GTK2
90         ? gdk_pixbuf_new_from_file (filename, &gerr)
91 #else
92         ? gdk_pixbuf_new_from_file (filename)
93 #endif /* HAVE_GTK2 */
94         : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
95   if (pb)
96     {
97       XImage *image;
98       int w = gdk_pixbuf_get_width (pb);
99       int h = gdk_pixbuf_get_height (pb);
100       guchar *row = gdk_pixbuf_get_pixels (pb);
101       int stride = gdk_pixbuf_get_rowstride (pb);
102       int chan = gdk_pixbuf_get_n_channels (pb);
103       int x, y;
104
105       image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
106       image->data = (char *) malloc(h * image->bytes_per_line);
107
108       /* Set the bit order in the XImage structure to whatever the
109          local host's native bit order is.
110        */
111       image->bitmap_bit_order =
112         image->byte_order =
113           (bigendian() ? MSBFirst : LSBFirst);
114
115
116       if (!image->data)
117         {
118           fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
119           exit (1);
120         }
121
122       for (y = 0; y < h; y++)
123         {
124           int y2 = (h-1-y); /* Texture maps are upside down. */
125
126           guchar *i = row;
127           for (x = 0; x < w; x++)
128             {
129               unsigned long rgba = 0;
130               switch (chan) {
131               case 1:
132                 rgba = ((0xFF << 24) |
133                         (*i << 16) |
134                         (*i << 8) |
135                          *i);
136                 i++;
137                 break;
138               case 3:
139                 rgba = ((0xFF << 24) |
140                         (i[2] << 16) |
141                         (i[1] << 8) |
142                          i[0]);
143                 i += 3;
144                 break;
145               case 4:
146                 rgba = ((i[3] << 24) |
147                         (i[2] << 16) |
148                         (i[1] << 8) |
149                          i[0]);
150                 i += 4;
151                 break;
152               default:
153                 abort();
154                 break;
155               }
156               XPutPixel (image, x, y2, rgba);
157             }
158           row += stride;
159         }
160       gdk_pixbuf_unref (pb); /* #### does doing this free colors? */
161
162       return image;
163     }
164   else if (filename)
165     {
166 #ifdef HAVE_GTK2
167       fprintf (stderr, "%s: %s\n", progname, gerr->message);
168       g_error_free (gerr);
169 #else
170       fprintf (stderr, "%s: unable to load %s\n", progname, filename);
171 #endif /* HAVE_GTK2 */
172       exit (1);
173     }
174   else
175     {
176       fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
177       exit (1);
178     }
179 }
180
181
182 #elif defined(HAVE_XPM)
183
184
185 #include <stdlib.h>
186 #include <stdio.h>
187 #include <X11/Intrinsic.h>
188
189 #include <X11/Xutil.h>
190 #include <X11/xpm.h>
191
192 #undef countof
193 #define countof(x) (sizeof((x))/sizeof((*x)))
194
195
196
197 /* The libxpm version of this function...
198  */
199 static XImage *
200 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
201                  const char *filename, char **xpm_data)
202 {
203   /* All we want to do is get RGB data out of the XPM file built in to this
204      program.  This is a pain, because there is no way  (as of XPM version
205      4.6, at least) to get libXpm to make an XImage without also allocating
206      colors with XAllocColor.  So, instead, we create an XpmImage and parse
207      out the RGB values of the pixels ourselves; and construct an XImage
208      by hand.  Regardless of the depth of the visual we're using, this
209      XImage will have 32 bits per pixel, 8 each per R, G, and B.  We put
210      0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
211    */
212   XImage *ximage = 0;
213   XpmImage xpm_image;
214   XpmInfo xpm_info;
215   int result;
216   int transparent_color_index = -1;
217   int x, y, i;
218   int bpl, wpl;
219   XColor colors[256];
220
221   memset (&xpm_image, 0, sizeof(xpm_image));
222   memset (&xpm_info, 0, sizeof(xpm_info));
223
224   if (filename)
225     {
226       xpm_data = 0;
227       if (! XpmReadFileToData ((char *) filename, &xpm_data))
228         {
229           fprintf (stderr, "%s: unable to read XPM file %s\n",
230                    progname, filename);
231           exit (1);
232         }
233     }
234
235   result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
236   if (result != XpmSuccess)
237     {
238       fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
239               result);
240       exit (1);
241     }
242
243   if (xpm_image.ncolors > countof(colors))
244     {
245       fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
246                progname, xpm_image.ncolors);
247       exit (1);
248     }
249
250   ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
251                          xpm_image.width, xpm_image.height, 32, 0);
252
253   bpl = ximage->bytes_per_line;
254   wpl = bpl/4;
255
256   ximage->data = (char *) malloc(xpm_image.height * bpl);
257
258   /* Parse the colors in the XPM into RGB values. */
259   for (i = 0; i < xpm_image.ncolors; i++)
260     {
261       const char *c = xpm_image.colorTable[i].c_color;
262       if (!c)
263         {
264           fprintf(stderr, "%s: bogus color table?  (%d)\n", progname, i);
265           exit (1);
266         }
267       else if (!strncasecmp (c, "None", 4))
268         {
269           transparent_color_index = i;
270           colors[transparent_color_index].red   = 0xFF;
271           colors[transparent_color_index].green = 0xFF;
272           colors[transparent_color_index].blue  = 0xFF;
273         }
274       else if (!XParseColor (dpy, cmap, c, &colors[i]))
275         {
276           fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
277           exit (1);
278         }
279     }
280
281   /* Translate the XpmImage to an RGB XImage. */
282   {
283     int rpos, gpos, bpos, apos;  /* bitfield positions */
284
285     /* Note that unlike X, which is endianness-agnostic (since any XImage
286        can have its own specific bit ordering, with the server reversing
287        things as necessary) OpenGL pretends everything is client-side, so
288        we need to pack things in the right order for the client machine.
289      */
290
291     ximage->bitmap_bit_order =
292       ximage->byte_order =
293         (bigendian() ? MSBFirst : LSBFirst);
294
295 #if 0
296     /* #### Cherub says that the little-endian case must be taken on MacOSX,
297             or else the colors/alpha are the wrong way around.  How can
298             that be the case?
299      */
300     if (bigendian())
301       rpos = 24, gpos = 16, bpos =  8, apos =  0;
302     else
303 #endif
304       rpos =  0, gpos =  8, bpos = 16, apos = 24;
305
306   }
307
308   /* I sure hope these only free the contents, and not the args. */
309 #if 0  /* Apparently not?  Gotta love those well-documented APIs! */
310   XpmFreeXpmImage (&xpm_image);
311   XpmFreeXpmInfo (&xpm_info);
312 #endif
313
314   return ximage;
315 }
316
317
318 #else  /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
319
320 /* If we don't have libXPM or Pixbuf, then use "minixpm".
321    This can read XPM data from memory, but can't read files.
322  */
323
324 #include <stdlib.h>
325 #include <stdio.h>
326 #include "minixpm.h"
327
328 #undef countof
329 #define countof(x) (sizeof((x))/sizeof((*x)))
330
331
332 /* Given a bitmask, returns the position and width of the field.
333  */
334 static void
335 decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret)
336 {
337   int i;
338   for (i = 0; i < 32; i++)
339     if (mask & (1L << i))
340       {
341         int j = 0;
342         *pos_ret = i;
343         for (; i < 32; i++, j++)
344           if (! (mask & (1L << i)))
345             break;
346         *size_ret = j;
347         return;
348       }
349 }
350
351
352 /* The minixpm version of this function...
353  */
354 static XImage *
355 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
356                  const char *filename, char **xpm_data)
357 {
358   int iw, ih, w8, x, y;
359   XImage *ximage;
360   char *data;
361   unsigned char *mask = 0;
362   int depth = 32;
363   unsigned long background_color =
364     BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
365   unsigned long *pixels = 0;
366   int npixels = 0;
367   int bpl;
368
369   unsigned int rpos=0, gpos=0, bpos=0, apos=0;
370   unsigned int rmsk=0, gmsk=0, bmsk=0, amsk=0;
371   unsigned int rsiz=0, gsiz=0, bsiz=0, asiz=0;
372
373   if (filename)
374     {
375       fprintf(stderr, 
376               "%s: no files: not compiled with XPM or Pixbuf support.\n", 
377               progname);
378       exit (1);
379     }
380
381   if (! xpm_data) abort();
382   ximage = minixpm_to_ximage (dpy, visual, cmap, depth, background_color,
383                               (const char * const *) xpm_data,
384                               &iw, &ih, &pixels, &npixels, &mask);
385   if (pixels) free (pixels);
386   
387   bpl = ximage->bytes_per_line;
388   data = ximage->data;
389   ximage->data = malloc (ximage->height * bpl);
390   
391   /* Flip image upside down, for texture maps; 
392      process the mask; and re-arrange the color components for GL.
393    */
394   w8 = (ximage->width + 7) / 8;
395
396   rmsk = ximage->red_mask;
397   gmsk = ximage->green_mask;
398   bmsk = ximage->blue_mask;
399   amsk = ~(rmsk|gmsk|bmsk);
400
401   decode_mask (rmsk, &rpos, &rsiz);
402   decode_mask (gmsk, &gpos, &gsiz);
403   decode_mask (bmsk, &bpos, &bsiz);
404   decode_mask (amsk, &apos, &asiz);
405
406   for (y = 0; y < ximage->height; y++)
407     {
408       int y2 = (ximage->height-1-y);
409     
410       unsigned int *oline = (unsigned int *) (ximage->data + (y  * bpl));
411       unsigned int *iline = (unsigned int *) (data         + (y2 * bpl));
412     
413       for (x = 0; x < ximage->width; x++)
414         {
415           unsigned long pixel = iline[x];
416           unsigned char r = (pixel & rmsk) >> rpos;
417           unsigned char g = (pixel & gmsk) >> gpos;
418           unsigned char b = (pixel & bmsk) >> bpos;
419           unsigned char a = (mask
420                              ? ((mask [(y2 * w8) + (x >> 3)] & (1 << (x % 8)))
421                                 ? 0xFF : 0)
422                              : 0xFF);
423 # if 0
424           pixel = ((r << rpos) | (g << gpos) | (b << bpos) | (a << apos));
425 # else
426           pixel = ((a << 24) | (b << 16) | (g <<  8) | r);
427 # endif
428           oline[x] = pixel;
429         }
430     }
431   free (data);
432
433   return ximage;
434 }
435
436 #endif /* !HAVE_XPM */
437
438
439 /* Returns an XImage structure containing the bits of the given XPM image.
440    This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
441    extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
442
443    The Display and Visual arguments are used only for creating the XImage;
444    no bits are pushed to the server.
445
446    The Colormap argument is used just for parsing color names; no colors
447    are allocated.
448  */
449 XImage *
450 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, 
451                char **xpm_data)
452 {
453   return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
454 }
455
456
457 XImage *
458 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
459                     const char *filename)
460 {
461   return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);
462 }