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>
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);
160 gdk_pixbuf_unref (pb); /* #### does doing this free colors? */
167 fprintf (stderr, "%s: %s\n", progname, gerr->message);
170 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
171 #endif /* HAVE_GTK2 */
176 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
182 #elif defined(HAVE_XPM)
187 #include <X11/Intrinsic.h>
189 #include <X11/Xutil.h>
193 #define countof(x) (sizeof((x))/sizeof((*x)))
197 /* The libxpm version of this function...
200 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
201 const char *filename, char **xpm_data)
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.
216 int transparent_color_index = -1;
221 memset (&xpm_image, 0, sizeof(xpm_image));
222 memset (&xpm_info, 0, sizeof(xpm_info));
227 if (! XpmReadFileToData ((char *) filename, &xpm_data))
229 fprintf (stderr, "%s: unable to read XPM file %s\n",
235 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
236 if (result != XpmSuccess)
238 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
243 if (xpm_image.ncolors > countof(colors))
245 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
246 progname, xpm_image.ncolors);
250 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
251 xpm_image.width, xpm_image.height, 32, 0);
253 bpl = ximage->bytes_per_line;
256 ximage->data = (char *) malloc(xpm_image.height * bpl);
258 /* Parse the colors in the XPM into RGB values. */
259 for (i = 0; i < xpm_image.ncolors; i++)
261 const char *c = xpm_image.colorTable[i].c_color;
264 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
267 else if (!strncasecmp (c, "None", 4))
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;
274 else if (!XParseColor (dpy, cmap, c, &colors[i]))
276 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
281 /* Translate the XpmImage to an RGB XImage. */
283 int rpos, gpos, bpos, apos; /* bitfield positions */
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.
291 ximage->bitmap_bit_order =
293 (bigendian() ? MSBFirst : LSBFirst);
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
301 rpos = 24, gpos = 16, bpos = 8, apos = 0;
304 rpos = 0, gpos = 8, bpos = 16, apos = 24;
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);
318 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
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.
329 #define countof(x) (sizeof((x))/sizeof((*x)))
332 /* Given a bitmask, returns the position and width of the field.
335 decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret)
338 for (i = 0; i < 32; i++)
339 if (mask & (1L << i))
343 for (; i < 32; i++, j++)
344 if (! (mask & (1L << i)))
352 /* The minixpm version of this function...
355 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
356 const char *filename, char **xpm_data)
358 int iw, ih, w8, x, y;
361 unsigned char *mask = 0;
363 unsigned long background_color =
364 BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
365 unsigned long *pixels = 0;
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;
376 "%s: no files: not compiled with XPM or Pixbuf support.\n",
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);
387 bpl = ximage->bytes_per_line;
389 ximage->data = malloc (ximage->height * bpl);
391 /* Flip image upside down, for texture maps;
392 process the mask; and re-arrange the color components for GL.
394 w8 = (ximage->width + 7) / 8;
396 rmsk = ximage->red_mask;
397 gmsk = ximage->green_mask;
398 bmsk = ximage->blue_mask;
399 amsk = ~(rmsk|gmsk|bmsk);
401 decode_mask (rmsk, &rpos, &rsiz);
402 decode_mask (gmsk, &gpos, &gsiz);
403 decode_mask (bmsk, &bpos, &bsiz);
404 decode_mask (amsk, &apos, &asiz);
406 for (y = 0; y < ximage->height; y++)
408 int y2 = (ximage->height-1-y);
410 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
411 unsigned int *iline = (unsigned int *) (data + (y2 * bpl));
413 for (x = 0; x < ximage->width; x++)
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)))
424 pixel = ((r << rpos) | (g << gpos) | (b << bpos) | (a << apos));
426 pixel = ((a << 24) | (b << 16) | (g << 8) | r);
436 #endif /* !HAVE_XPM */
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.)
443 The Display and Visual arguments are used only for creating the XImage;
444 no bits are pushed to the server.
446 The Colormap argument is used just for parsing color names; no colors
450 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
453 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
458 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
459 const char *filename)
461 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);