1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 1998-2003 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>
23 extern char *progname;
26 #if defined(HAVE_GDK_PIXBUF)
28 # include <gdk-pixbuf/gdk-pixbuf.h>
31 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
32 # else /* !HAVE_GTK2 */
33 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
34 # endif /* !HAVE_GTK2 */
37 /* Returns an XImage structure containing the bits of the given XPM image.
38 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
39 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
41 The Display and Visual arguments are used only for creating the XImage;
42 no bits are pushed to the server.
44 The Colormap argument is used just for parsing color names; no colors
47 This is the gdk_pixbuf version of this function.
50 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
55 static int initted = 0;
65 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
66 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
72 ? gdk_pixbuf_new_from_file (filename, &gerr)
74 ? gdk_pixbuf_new_from_file (filename)
75 #endif /* HAVE_GTK2 */
76 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
80 int w = gdk_pixbuf_get_width (pb);
81 int h = gdk_pixbuf_get_height (pb);
82 guchar *row = gdk_pixbuf_get_pixels (pb);
83 int stride = gdk_pixbuf_get_rowstride (pb);
84 int chan = gdk_pixbuf_get_n_channels (pb);
87 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
88 image->data = (char *) malloc(h * image->bytes_per_line);
91 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
95 for (y = 0; y < h; y++)
97 int y2 = (h-1-y); /* Texture maps are upside down. */
100 for (x = 0; x < w; x++)
102 unsigned long rgba = 0;
105 rgba = ((0xFF << 24) |
112 rgba = ((0xFF << 24) |
119 rgba = ((i[3] << 24) |
129 XPutPixel (image, x, y2, rgba);
133 gdk_pixbuf_unref (pb); /* #### does doing this free colors? */
140 fprintf (stderr, "%s: %s\n", progname, gerr->message);
143 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
144 #endif /* HAVE_GTK2 */
149 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
155 #elif defined(HAVE_XPM)
160 #include <X11/Intrinsic.h>
162 #include <X11/Xutil.h>
166 #define countof(x) (sizeof((x))/sizeof((*x)))
172 union { int i; char c[sizeof(int)]; } u;
179 /* The libxpm version of this function...
182 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
183 const char *filename, char **xpm_data)
185 /* All we want to do is get RGB data out of the XPM file built in to this
186 program. This is a pain, because there is no way (as of XPM version
187 4.6, at least) to get libXpm to make an XImage without also allocating
188 colors with XAllocColor. So, instead, we create an XpmImage and parse
189 out the RGB values of the pixels ourselves; and construct an XImage
190 by hand. Regardless of the depth of the visual we're using, this
191 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
192 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
198 int transparent_color_index = -1;
203 memset (&xpm_image, 0, sizeof(xpm_image));
204 memset (&xpm_info, 0, sizeof(xpm_info));
209 if (! XpmReadFileToData ((char *) filename, &xpm_data))
211 fprintf (stderr, "%s: unable to read XPM file %s\n",
217 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
218 if (result != XpmSuccess)
220 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
225 if (xpm_image.ncolors > countof(colors))
227 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
228 progname, xpm_image.ncolors);
232 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
233 xpm_image.width, xpm_image.height, 32, 0);
235 bpl = ximage->bytes_per_line;
238 ximage->data = (char *) malloc(xpm_image.height * bpl);
240 /* Parse the colors in the XPM into RGB values. */
241 for (i = 0; i < xpm_image.ncolors; i++)
243 const char *c = xpm_image.colorTable[i].c_color;
246 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
249 else if (!strncasecmp (c, "None", 4))
251 transparent_color_index = i;
252 colors[transparent_color_index].red = 0xFF;
253 colors[transparent_color_index].green = 0xFF;
254 colors[transparent_color_index].blue = 0xFF;
256 else if (!XParseColor (dpy, cmap, c, &colors[i]))
258 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
263 /* Translate the XpmImage to an RGB XImage. */
265 int rpos, gpos, bpos, apos; /* bitfield positions */
267 /* Note that unlike X, which is endianness-agnostic (since any XImage
268 can have its own specific bit ordering, with the server reversing
269 things as necessary) OpenGL pretends everything is client-side, so
270 we need to pack things in the right order for the client machine.
273 /* #### Cherub says that the little-endian case must be taken on MacOSX,
274 or else the colors/alpha are the wrong way around. How can
278 rpos = 24, gpos = 16, bpos = 8, apos = 0;
281 rpos = 0, gpos = 8, bpos = 16, apos = 24;
283 for (y = 0; y < xpm_image.height; y++)
285 int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
287 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
288 unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
290 for (x = 0; x < xpm_image.width; x++)
292 XColor *c = &colors[iline[x]];
293 int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
294 oline[x] = (((c->red >> 8) << rpos) |
295 ((c->green >> 8) << gpos) |
296 ((c->blue >> 8) << bpos) |
302 /* I sure hope these only free the contents, and not the args. */
303 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
304 XpmFreeXpmImage (&xpm_image);
305 XpmFreeXpmInfo (&xpm_info);
312 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
315 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
316 const char *filename, char **xpm_data)
318 fprintf(stderr, "%s: not compiled with XPM or Pixbuf support.\n", progname);
322 #endif /* !HAVE_XPM */
325 /* Returns an XImage structure containing the bits of the given XPM image.
326 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
327 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
329 The Display and Visual arguments are used only for creating the XImage;
330 no bits are pushed to the server.
332 The Colormap argument is used just for parsing color names; no colors
336 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
338 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
343 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
344 const char *filename)
346 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);