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>
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
12 * Alpha channel support by Eric Lassauge <lassauge@users.sourceforge.net>
25 # include <X11/Xlib.h>
28 #include "xpm-ximage.h"
30 extern char *progname;
33 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
37 union { int i; char c[sizeof(int)]; } u;
41 #endif /* HAVE_GDK_PIXBUF || HAVE_XPM */
44 #if defined(HAVE_GDK_PIXBUF)
46 # include <gdk-pixbuf/gdk-pixbuf.h>
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 */
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.)
59 The Display and Visual arguments are used only for creating the XImage;
60 no bits are pushed to the server.
62 The Colormap argument is used just for parsing color names; no colors
65 This is the gdk_pixbuf version of this function.
68 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
73 static int initted = 0;
81 #if !GLIB_CHECK_VERSION(2, 36 ,0)
85 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
86 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
92 ? gdk_pixbuf_new_from_file (filename, &gerr)
94 ? gdk_pixbuf_new_from_file (filename)
95 #endif /* HAVE_GTK2 */
96 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
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);
107 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
108 image->data = (char *) malloc(h * image->bytes_per_line);
110 /* Set the bit order in the XImage structure to whatever the
111 local host's native bit order is.
113 image->bitmap_bit_order =
115 (bigendian() ? MSBFirst : LSBFirst);
120 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
124 for (y = 0; y < h; y++)
126 int y2 = (h-1-y); /* Texture maps are upside down. */
129 for (x = 0; x < w; x++)
131 unsigned long rgba = 0;
134 rgba = ((0xFF << 24) |
141 rgba = ((0xFF << 24) |
148 rgba = ((i[3] << 24) |
158 XPutPixel (image, x, y2, rgba);
163 /* #### are colors getting freed here? */
171 fprintf (stderr, "%s: %s\n", progname, gerr->message);
174 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
175 #endif /* HAVE_GTK2 */
180 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
186 #elif defined(HAVE_XPM)
191 #include <X11/Intrinsic.h>
193 #include <X11/Xutil.h>
197 #define countof(x) (sizeof((x))/sizeof((*x)))
201 /* The libxpm version of this function...
204 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
205 const char *filename, char **xpm_data)
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.
220 int transparent_color_index = -1;
225 memset (&xpm_image, 0, sizeof(xpm_image));
226 memset (&xpm_info, 0, sizeof(xpm_info));
231 if (XpmSuccess != XpmReadFileToData ((char *) filename, &xpm_data))
233 fprintf (stderr, "%s: unable to read XPM file %s\n",
239 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
240 if (result != XpmSuccess)
242 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
247 if (xpm_image.ncolors > countof(colors))
249 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
250 progname, xpm_image.ncolors);
254 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
255 xpm_image.width, xpm_image.height, 32, 0);
257 bpl = ximage->bytes_per_line;
260 ximage->data = (char *) malloc(xpm_image.height * bpl);
262 /* Parse the colors in the XPM into RGB values. */
263 for (i = 0; i < xpm_image.ncolors; i++)
265 const char *c = xpm_image.colorTable[i].c_color;
268 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
271 else if (!strncasecmp (c, "None", 4))
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;
278 else if (!XParseColor (dpy, cmap, c, &colors[i]))
280 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
285 /* Translate the XpmImage to an RGB XImage. */
287 int rpos, gpos, bpos, apos; /* bitfield positions */
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.
295 ximage->bitmap_bit_order =
297 (bigendian() ? MSBFirst : LSBFirst);
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
305 rpos = 24, gpos = 16, bpos = 8, apos = 0;
308 rpos = 0, gpos = 8, bpos = 16, apos = 24;
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);
322 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
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.
333 #define countof(x) (sizeof((x))/sizeof((*x)))
336 /* Given a bitmask, returns the position and width of the field.
339 decode_mask (unsigned long mask, unsigned long *pos_ret,
340 unsigned long *size_ret)
343 for (i = 0; i < 32; i++)
344 if (mask & (1L << i))
348 for (; i < 32; i++, j++)
349 if (! (mask & (1L << i)))
357 /* The minixpm version of this function...
360 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
361 const char *filename, char **xpm_data)
363 int iw, ih, w8, x, y;
366 unsigned char *mask = 0;
368 unsigned long background_color =
369 BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
370 unsigned long *pixels = 0;
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;
381 "%s: no files: not compiled with XPM or Pixbuf support.\n",
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);
392 bpl = ximage->bytes_per_line;
394 ximage->data = malloc (ximage->height * bpl);
396 /* Flip image upside down, for texture maps;
397 process the mask; and re-arrange the color components for GL.
399 w8 = (ximage->width + 7) / 8;
401 rmsk = ximage->red_mask;
402 gmsk = ximage->green_mask;
403 bmsk = ximage->blue_mask;
404 amsk = ~(rmsk|gmsk|bmsk);
406 decode_mask (rmsk, &rpos, &rsiz);
407 decode_mask (gmsk, &gpos, &gsiz);
408 decode_mask (bmsk, &bpos, &bsiz);
409 decode_mask (amsk, &apos, &asiz);
411 for (y = 0; y < ximage->height; y++)
413 int y2 = (ximage->height-1-y);
415 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
416 unsigned int *iline = (unsigned int *) (data + (y2 * bpl));
418 for (x = 0; x < ximage->width; x++)
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)))
429 pixel = ((r << rpos) | (g << gpos) | (b << bpos) | (a << apos));
431 pixel = ((a << 24) | (b << 16) | (g << 8) | r);
441 #endif /* !HAVE_XPM */
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.)
448 The Display and Visual arguments are used only for creating the XImage;
449 no bits are pushed to the server.
451 The Colormap argument is used just for parsing color names; no colors
455 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
458 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
463 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
464 const char *filename)
466 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);