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;
29 union { int i; char c[sizeof(int)]; } u;
35 #if defined(HAVE_GDK_PIXBUF)
37 # include <gdk-pixbuf/gdk-pixbuf.h>
40 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
41 # else /* !HAVE_GTK2 */
42 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
43 # endif /* !HAVE_GTK2 */
46 /* Returns an XImage structure containing the bits of the given XPM image.
47 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
48 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
50 The Display and Visual arguments are used only for creating the XImage;
51 no bits are pushed to the server.
53 The Colormap argument is used just for parsing color names; no colors
56 This is the gdk_pixbuf version of this function.
59 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
64 static int initted = 0;
74 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
75 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
81 ? gdk_pixbuf_new_from_file (filename, &gerr)
83 ? gdk_pixbuf_new_from_file (filename)
84 #endif /* HAVE_GTK2 */
85 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
89 int w = gdk_pixbuf_get_width (pb);
90 int h = gdk_pixbuf_get_height (pb);
91 guchar *row = gdk_pixbuf_get_pixels (pb);
92 int stride = gdk_pixbuf_get_rowstride (pb);
93 int chan = gdk_pixbuf_get_n_channels (pb);
96 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
97 image->data = (char *) malloc(h * image->bytes_per_line);
99 /* Set the bit order in the XImage structure to whatever the
100 local host's native bit order is.
102 image->bitmap_bit_order =
104 (bigendian() ? MSBFirst : LSBFirst);
109 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
113 for (y = 0; y < h; y++)
115 int y2 = (h-1-y); /* Texture maps are upside down. */
118 for (x = 0; x < w; x++)
120 unsigned long rgba = 0;
123 rgba = ((0xFF << 24) |
130 rgba = ((0xFF << 24) |
137 rgba = ((i[3] << 24) |
147 XPutPixel (image, x, y2, rgba);
151 gdk_pixbuf_unref (pb); /* #### does doing this free colors? */
158 fprintf (stderr, "%s: %s\n", progname, gerr->message);
161 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
162 #endif /* HAVE_GTK2 */
167 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
173 #elif defined(HAVE_XPM)
178 #include <X11/Intrinsic.h>
180 #include <X11/Xutil.h>
184 #define countof(x) (sizeof((x))/sizeof((*x)))
188 /* The libxpm version of this function...
191 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
192 const char *filename, char **xpm_data)
194 /* All we want to do is get RGB data out of the XPM file built in to this
195 program. This is a pain, because there is no way (as of XPM version
196 4.6, at least) to get libXpm to make an XImage without also allocating
197 colors with XAllocColor. So, instead, we create an XpmImage and parse
198 out the RGB values of the pixels ourselves; and construct an XImage
199 by hand. Regardless of the depth of the visual we're using, this
200 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
201 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
207 int transparent_color_index = -1;
212 memset (&xpm_image, 0, sizeof(xpm_image));
213 memset (&xpm_info, 0, sizeof(xpm_info));
218 if (! XpmReadFileToData ((char *) filename, &xpm_data))
220 fprintf (stderr, "%s: unable to read XPM file %s\n",
226 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
227 if (result != XpmSuccess)
229 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
234 if (xpm_image.ncolors > countof(colors))
236 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
237 progname, xpm_image.ncolors);
241 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
242 xpm_image.width, xpm_image.height, 32, 0);
244 bpl = ximage->bytes_per_line;
247 ximage->data = (char *) malloc(xpm_image.height * bpl);
249 /* Parse the colors in the XPM into RGB values. */
250 for (i = 0; i < xpm_image.ncolors; i++)
252 const char *c = xpm_image.colorTable[i].c_color;
255 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
258 else if (!strncasecmp (c, "None", 4))
260 transparent_color_index = i;
261 colors[transparent_color_index].red = 0xFF;
262 colors[transparent_color_index].green = 0xFF;
263 colors[transparent_color_index].blue = 0xFF;
265 else if (!XParseColor (dpy, cmap, c, &colors[i]))
267 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
272 /* Translate the XpmImage to an RGB XImage. */
274 int rpos, gpos, bpos, apos; /* bitfield positions */
276 /* Note that unlike X, which is endianness-agnostic (since any XImage
277 can have its own specific bit ordering, with the server reversing
278 things as necessary) OpenGL pretends everything is client-side, so
279 we need to pack things in the right order for the client machine.
282 ximage->bitmap_bit_order =
284 (bigendian() ? MSBFirst : LSBFirst);
287 /* #### Cherub says that the little-endian case must be taken on MacOSX,
288 or else the colors/alpha are the wrong way around. How can
292 rpos = 24, gpos = 16, bpos = 8, apos = 0;
295 rpos = 0, gpos = 8, bpos = 16, apos = 24;
297 for (y = 0; y < xpm_image.height; y++)
299 int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
301 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
302 unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
304 for (x = 0; x < xpm_image.width; x++)
306 XColor *c = &colors[iline[x]];
307 int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
308 oline[x] = (((c->red >> 8) << rpos) |
309 ((c->green >> 8) << gpos) |
310 ((c->blue >> 8) << bpos) |
316 /* I sure hope these only free the contents, and not the args. */
317 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
318 XpmFreeXpmImage (&xpm_image);
319 XpmFreeXpmInfo (&xpm_info);
326 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
329 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
330 const char *filename, char **xpm_data)
332 fprintf(stderr, "%s: not compiled with XPM or Pixbuf support.\n", progname);
336 #endif /* !HAVE_XPM */
339 /* Returns an XImage structure containing the bits of the given XPM image.
340 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
341 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
343 The Display and Visual arguments are used only for creating the XImage;
344 no bits are pushed to the server.
346 The Colormap argument is used just for parsing color names; no colors
350 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
352 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
357 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
358 const char *filename)
360 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);