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@mail.dotcom.fr>.
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)))
171 union { int i; char c[sizeof(int)]; } u;
177 /* The libxpm version of this function...
180 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
181 const char *filename, char **xpm_data)
183 /* All we want to do is get RGB data out of the XPM file built in to this
184 program. This is a pain, because there is no way (as of XPM version
185 4.6, at least) to get libXpm to make an XImage without also allocating
186 colors with XAllocColor. So, instead, we create an XpmImage and parse
187 out the RGB values of the pixels ourselves; and construct an XImage
188 by hand. Regardless of the depth of the visual we're using, this
189 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
190 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
196 int transparent_color_index = -1;
201 memset (&xpm_image, 0, sizeof(xpm_image));
202 memset (&xpm_info, 0, sizeof(xpm_info));
207 if (! XpmReadFileToData ((char *) filename, &xpm_data))
209 fprintf (stderr, "%s: unable to read XPM file %s\n",
215 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
216 if (result != XpmSuccess)
218 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
223 if (xpm_image.ncolors > countof(colors))
225 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
226 progname, xpm_image.ncolors);
230 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
231 xpm_image.width, xpm_image.height, 32, 0);
233 bpl = ximage->bytes_per_line;
236 ximage->data = (char *) malloc(xpm_image.height * bpl);
238 /* Parse the colors in the XPM into RGB values. */
239 for (i = 0; i < xpm_image.ncolors; i++)
241 const char *c = xpm_image.colorTable[i].c_color;
244 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
247 else if (!strncasecmp (c, "None", 4))
249 transparent_color_index = i;
250 colors[transparent_color_index].red = 0xFF;
251 colors[transparent_color_index].green = 0xFF;
252 colors[transparent_color_index].blue = 0xFF;
254 else if (!XParseColor (dpy, cmap, c, &colors[i]))
256 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
261 /* Translate the XpmImage to an RGB XImage. */
263 int rpos, gpos, bpos, apos; /* bitfield positions */
265 /* Note that unlike X, which is endianness-agnostic (since any XImage
266 can have its own specific bit ordering, with the server reversing
267 things as necessary) OpenGL pretends everything is client-side, so
268 we need to pack things in the right order for the client machine.
271 rpos = 24, gpos = 16, bpos = 8, apos = 0;
273 rpos = 0, gpos = 8, bpos = 16, apos = 24;
275 for (y = 0; y < xpm_image.height; y++)
277 int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
279 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
280 unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
282 for (x = 0; x < xpm_image.width; x++)
284 XColor *c = &colors[iline[x]];
285 int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
286 oline[x] = (((c->red >> 8) << rpos) |
287 ((c->green >> 8) << gpos) |
288 ((c->blue >> 8) << bpos) |
294 /* I sure hope these only free the contents, and not the args. */
295 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
296 XpmFreeXpmImage (&xpm_image);
297 XpmFreeXpmInfo (&xpm_info);
304 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
307 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
308 const char *filename, char **xpm_data)
310 fprintf(stderr, "%s: not compiled with XPM or Pixbuf support.\n", progname);
314 #endif /* !HAVE_XPM */
317 /* Returns an XImage structure containing the bits of the given XPM image.
318 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
319 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
321 The Display and Visual arguments are used only for creating the XImage;
322 no bits are pushed to the server.
324 The Colormap argument is used just for parsing color names; no colors
328 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
330 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
335 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
336 const char *filename)
338 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);