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