1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 1998, 2001 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>.
21 #include <X11/Intrinsic.h>
23 extern char *progname;
25 #ifdef HAVE_XPM /* whole file */
27 #include <X11/Xutil.h>
31 #define countof(x) (sizeof((x))/sizeof((*x)))
36 union { int i; char c[sizeof(int)]; } u;
42 /* Returns an XImage structure containing the bits of the given XPM image.
43 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
44 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
46 The Display and Visual arguments are used only for creating the XImage;
47 no bits are pushed to the server.
49 The Colormap argument is used just for parsing color names; no colors
53 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
55 /* All we want to do is get RGB data out of the XPM file built in to this
56 program. This is a pain, because there is no way (as of XPM version
57 4.6, at least) to get libXpm to make an XImage without also allocating
58 colors with XAllocColor. So, instead, we create an XpmImage and parse
59 out the RGB values of the pixels ourselves; and construct an XImage
60 by hand. Regardless of the depth of the visual we're using, this
61 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
62 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
68 int transparent_color_index = -1;
73 memset (&xpm_image, 0, sizeof(xpm_image));
74 memset (&xpm_info, 0, sizeof(xpm_info));
75 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
76 if (result != XpmSuccess)
78 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
83 if (xpm_image.ncolors > countof(colors))
85 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
86 progname, xpm_image.ncolors);
90 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
91 xpm_image.width, xpm_image.height, 32, 0);
93 bpl = ximage->bytes_per_line;
96 ximage->data = (char *) malloc(xpm_image.height * bpl);
98 /* Parse the colors in the XPM into RGB values. */
99 for (i = 0; i < xpm_image.ncolors; i++)
101 const char *c = xpm_image.colorTable[i].c_color;
104 fprintf(stderr, "%s: bogus color table? ($d)\n", progname, i);
107 else if (!strncasecmp (c, "None", 4))
109 transparent_color_index = i;
110 colors[transparent_color_index].red = 0xFF;
111 colors[transparent_color_index].green = 0xFF;
112 colors[transparent_color_index].blue = 0xFF;
114 else if (!XParseColor (dpy, cmap, c, &colors[i]))
116 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
121 /* Translate the XpmImage to an RGB XImage. */
123 int rpos, gpos, bpos, apos; /* bitfield positions */
125 /* Note that unlike X, which is endianness-agnostic (since any XImage
126 can have its own specific bit ordering, with the server reversing
127 things as necessary) OpenGL pretends everything is client-side, so
128 we need to pack things in the right order for the client machine.
131 rpos = 24, gpos = 16, bpos = 8, apos = 0;
133 rpos = 0, gpos = 8, bpos = 16, apos = 24;
135 for (y = 0; y < xpm_image.height; y++)
137 int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
139 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
140 unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
142 for (x = 0; x < xpm_image.width; x++)
144 XColor *c = &colors[iline[x]];
145 int alpha = ((iline[x] == transparent_color_index) ? 0x00 : 0xFF);
146 oline[x] = (((c->red >> 8) << rpos) |
147 ((c->green >> 8) << gpos) |
148 ((c->blue >> 8) << bpos) |
154 /* I sure hope these only free the contents, and not the args. */
155 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
156 XpmFreeXpmImage (&xpm_image);
157 XpmFreeXpmInfo (&xpm_info);
164 #else /* !HAVE_XPM */
167 xpm_to_ximage (char **xpm_data)
169 fprintf(stderr, "%s: not compiled with XPM support.\n", progname);
173 #endif /* !HAVE_XPM */