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;
83 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
84 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
90 ? gdk_pixbuf_new_from_file (filename, &gerr)
92 ? gdk_pixbuf_new_from_file (filename)
93 #endif /* HAVE_GTK2 */
94 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
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);
105 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
106 image->data = (char *) malloc(h * image->bytes_per_line);
108 /* Set the bit order in the XImage structure to whatever the
109 local host's native bit order is.
111 image->bitmap_bit_order =
113 (bigendian() ? MSBFirst : LSBFirst);
118 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
122 for (y = 0; y < h; y++)
124 int y2 = (h-1-y); /* Texture maps are upside down. */
127 for (x = 0; x < w; x++)
129 unsigned long rgba = 0;
132 rgba = ((0xFF << 24) |
139 rgba = ((0xFF << 24) |
146 rgba = ((i[3] << 24) |
156 XPutPixel (image, x, y2, rgba);
161 /* #### are colors getting freed here? */
169 fprintf (stderr, "%s: %s\n", progname, gerr->message);
172 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
173 #endif /* HAVE_GTK2 */
178 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
184 #elif defined(HAVE_XPM)
189 #include <X11/Intrinsic.h>
191 #include <X11/Xutil.h>
195 #define countof(x) (sizeof((x))/sizeof((*x)))
199 /* The libxpm version of this function...
202 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
203 const char *filename, char **xpm_data)
205 /* All we want to do is get RGB data out of the XPM file built in to this
206 program. This is a pain, because there is no way (as of XPM version
207 4.6, at least) to get libXpm to make an XImage without also allocating
208 colors with XAllocColor. So, instead, we create an XpmImage and parse
209 out the RGB values of the pixels ourselves; and construct an XImage
210 by hand. Regardless of the depth of the visual we're using, this
211 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
212 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
218 int transparent_color_index = -1;
223 memset (&xpm_image, 0, sizeof(xpm_image));
224 memset (&xpm_info, 0, sizeof(xpm_info));
229 if (XpmSuccess != XpmReadFileToData ((char *) filename, &xpm_data))
231 fprintf (stderr, "%s: unable to read XPM file %s\n",
237 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
238 if (result != XpmSuccess)
240 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
245 if (xpm_image.ncolors > countof(colors))
247 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
248 progname, xpm_image.ncolors);
252 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
253 xpm_image.width, xpm_image.height, 32, 0);
255 bpl = ximage->bytes_per_line;
258 ximage->data = (char *) malloc(xpm_image.height * bpl);
260 /* Parse the colors in the XPM into RGB values. */
261 for (i = 0; i < xpm_image.ncolors; i++)
263 const char *c = xpm_image.colorTable[i].c_color;
266 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
269 else if (!strncasecmp (c, "None", 4))
271 transparent_color_index = i;
272 colors[transparent_color_index].red = 0xFF;
273 colors[transparent_color_index].green = 0xFF;
274 colors[transparent_color_index].blue = 0xFF;
276 else if (!XParseColor (dpy, cmap, c, &colors[i]))
278 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
283 /* Translate the XpmImage to an RGB XImage. */
285 int rpos, gpos, bpos, apos; /* bitfield positions */
287 /* Note that unlike X, which is endianness-agnostic (since any XImage
288 can have its own specific bit ordering, with the server reversing
289 things as necessary) OpenGL pretends everything is client-side, so
290 we need to pack things in the right order for the client machine.
293 ximage->bitmap_bit_order =
295 (bigendian() ? MSBFirst : LSBFirst);
298 /* #### Cherub says that the little-endian case must be taken on MacOSX,
299 or else the colors/alpha are the wrong way around. How can
303 rpos = 24, gpos = 16, bpos = 8, apos = 0;
306 rpos = 0, gpos = 8, bpos = 16, apos = 24;
310 /* I sure hope these only free the contents, and not the args. */
311 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
312 XpmFreeXpmImage (&xpm_image);
313 XpmFreeXpmInfo (&xpm_info);
320 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
322 /* If we don't have libXPM or Pixbuf, then use "minixpm".
323 This can read XPM data from memory, but can't read files.
331 #define countof(x) (sizeof((x))/sizeof((*x)))
334 /* Given a bitmask, returns the position and width of the field.
337 decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret)
340 for (i = 0; i < 32; i++)
341 if (mask & (1L << i))
345 for (; i < 32; i++, j++)
346 if (! (mask & (1L << i)))
354 /* The minixpm version of this function...
357 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
358 const char *filename, char **xpm_data)
360 int iw, ih, w8, x, y;
363 unsigned char *mask = 0;
365 unsigned long background_color =
366 BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
367 unsigned long *pixels = 0;
371 unsigned int rpos=0, gpos=0, bpos=0, apos=0;
372 unsigned int rmsk=0, gmsk=0, bmsk=0, amsk=0;
373 unsigned int rsiz=0, gsiz=0, bsiz=0, asiz=0;
378 "%s: no files: not compiled with XPM or Pixbuf support.\n",
383 if (! xpm_data) abort();
384 ximage = minixpm_to_ximage (dpy, visual, cmap, depth, background_color,
385 (const char * const *) xpm_data,
386 &iw, &ih, &pixels, &npixels, &mask);
387 if (pixels) free (pixels);
389 bpl = ximage->bytes_per_line;
391 ximage->data = malloc (ximage->height * bpl);
393 /* Flip image upside down, for texture maps;
394 process the mask; and re-arrange the color components for GL.
396 w8 = (ximage->width + 7) / 8;
398 rmsk = ximage->red_mask;
399 gmsk = ximage->green_mask;
400 bmsk = ximage->blue_mask;
401 amsk = ~(rmsk|gmsk|bmsk);
403 decode_mask (rmsk, &rpos, &rsiz);
404 decode_mask (gmsk, &gpos, &gsiz);
405 decode_mask (bmsk, &bpos, &bsiz);
406 decode_mask (amsk, &apos, &asiz);
408 for (y = 0; y < ximage->height; y++)
410 int y2 = (ximage->height-1-y);
412 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
413 unsigned int *iline = (unsigned int *) (data + (y2 * bpl));
415 for (x = 0; x < ximage->width; x++)
417 unsigned long pixel = iline[x];
418 unsigned char r = (pixel & rmsk) >> rpos;
419 unsigned char g = (pixel & gmsk) >> gpos;
420 unsigned char b = (pixel & bmsk) >> bpos;
421 unsigned char a = (mask
422 ? ((mask [(y2 * w8) + (x >> 3)] & (1 << (x % 8)))
426 pixel = ((r << rpos) | (g << gpos) | (b << bpos) | (a << apos));
428 pixel = ((a << 24) | (b << 16) | (g << 8) | r);
438 #endif /* !HAVE_XPM */
441 /* Returns an XImage structure containing the bits of the given XPM image.
442 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
443 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
445 The Display and Visual arguments are used only for creating the XImage;
446 no bits are pushed to the server.
448 The Colormap argument is used just for parsing color names; no colors
452 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
455 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
460 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
461 const char *filename)
463 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);