1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 1998, 2001, 2002 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>.
22 extern char *progname;
25 #if defined(HAVE_GDK_PIXBUF)
27 # include <gdk-pixbuf/gdk-pixbuf.h>
30 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
31 # else /* !HAVE_GTK2 */
32 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
33 # endif /* !HAVE_GTK2 */
36 /* Returns an XImage structure containing the bits of the given XPM image.
37 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
38 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
40 The Display and Visual arguments are used only for creating the XImage;
41 no bits are pushed to the server.
43 The Colormap argument is used just for parsing color names; no colors
46 This is the gdk_pixbuf version of this function.
49 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
54 static int initted = 0;
64 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
65 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
71 ? gdk_pixbuf_new_from_file (filename, &gerr)
73 ? gdk_pixbuf_new_from_file (filename)
74 #endif /* HAVE_GTK2 */
75 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
79 int w = gdk_pixbuf_get_width (pb);
80 int h = gdk_pixbuf_get_height (pb);
81 guchar *row = gdk_pixbuf_get_pixels (pb);
82 int stride = gdk_pixbuf_get_rowstride (pb);
83 int chan = gdk_pixbuf_get_n_channels (pb);
86 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
87 image->data = (char *) malloc(h * image->bytes_per_line);
90 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
94 for (y = 0; y < h; y++)
96 int y2 = (h-1-y); /* Texture maps are upside down. */
99 for (x = 0; x < w; x++)
101 unsigned long rgba = 0;
104 rgba = ((0xFF << 24) |
111 rgba = ((0xFF << 24) |
118 rgba = ((i[3] << 24) |
128 XPutPixel (image, x, y2, rgba);
132 gdk_pixbuf_unref (pb); /* #### does doing this free colors? */
139 fprintf (stderr, "%s: %s\n", progname, gerr->message);
142 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
143 #endif /* HAVE_GTK2 */
148 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
154 #elif defined(HAVE_XPM)
159 #include <X11/Intrinsic.h>
161 #include <X11/Xutil.h>
165 #define countof(x) (sizeof((x))/sizeof((*x)))
170 union { int i; char c[sizeof(int)]; } u;
176 /* The libxpm version of this function...
179 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
180 const char *filename, char **xpm_data)
182 /* All we want to do is get RGB data out of the XPM file built in to this
183 program. This is a pain, because there is no way (as of XPM version
184 4.6, at least) to get libXpm to make an XImage without also allocating
185 colors with XAllocColor. So, instead, we create an XpmImage and parse
186 out the RGB values of the pixels ourselves; and construct an XImage
187 by hand. Regardless of the depth of the visual we're using, this
188 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
189 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
195 int transparent_color_index = -1;
200 memset (&xpm_image, 0, sizeof(xpm_image));
201 memset (&xpm_info, 0, sizeof(xpm_info));
206 if (! XpmReadFileToData ((char *) filename, &xpm_data))
208 fprintf (stderr, "%s: unable to read XPM file %f\n",
214 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
215 if (result != XpmSuccess)
217 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
222 if (xpm_image.ncolors > countof(colors))
224 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
225 progname, xpm_image.ncolors);
229 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
230 xpm_image.width, xpm_image.height, 32, 0);
232 bpl = ximage->bytes_per_line;
235 ximage->data = (char *) malloc(xpm_image.height * bpl);
237 /* Parse the colors in the XPM into RGB values. */
238 for (i = 0; i < xpm_image.ncolors; i++)
240 const char *c = xpm_image.colorTable[i].c_color;
243 fprintf(stderr, "%s: bogus color table? ($d)\n", progname, i);
246 else if (!strncasecmp (c, "None", 4))
248 transparent_color_index = i;
249 colors[transparent_color_index].red = 0xFF;
250 colors[transparent_color_index].green = 0xFF;
251 colors[transparent_color_index].blue = 0xFF;
253 else if (!XParseColor (dpy, cmap, c, &colors[i]))
255 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
260 /* Translate the XpmImage to an RGB XImage. */
262 int rpos, gpos, bpos, apos; /* bitfield positions */
264 /* Note that unlike X, which is endianness-agnostic (since any XImage
265 can have its own specific bit ordering, with the server reversing
266 things as necessary) OpenGL pretends everything is client-side, so
267 we need to pack things in the right order for the client machine.
270 rpos = 24, gpos = 16, bpos = 8, apos = 0;
272 rpos = 0, gpos = 8, bpos = 16, apos = 24;
274 for (y = 0; y < xpm_image.height; y++)
276 int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
278 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
279 unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
281 for (x = 0; x < xpm_image.width; x++)
283 XColor *c = &colors[iline[x]];
284 int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
285 oline[x] = (((c->red >> 8) << rpos) |
286 ((c->green >> 8) << gpos) |
287 ((c->blue >> 8) << bpos) |
293 /* I sure hope these only free the contents, and not the args. */
294 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
295 XpmFreeXpmImage (&xpm_image);
296 XpmFreeXpmInfo (&xpm_info);
303 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
306 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
307 const char *filename, char **xpm_data)
309 fprintf(stderr, "%s: not compiled with XPM or Pixbuf support.\n", progname);
313 #endif /* !HAVE_XPM */
316 /* Returns an XImage structure containing the bits of the given XPM image.
317 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
318 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
320 The Display and Visual arguments are used only for creating the XImage;
321 no bits are pushed to the server.
323 The Colormap argument is used just for parsing color names; no colors
327 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
329 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
334 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
335 const char *filename)
337 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);