5913ddddac05b4474b8e34a3a3c20f10badb8ac2
[xscreensaver] / hacks / glx / xpm-ximage.c
1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2  * xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #ifdef HAVE_XPM         /* whole file */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <X11/Intrinsic.h>
22 #include <X11/Xutil.h>
23 #include <X11/xpm.h>
24
25 extern char *progname;
26
27 static Bool
28 bigendian (void)
29 {
30   union { int i; char c[sizeof(int)]; } u;
31   u.i = 1;
32   return !u.c[0];
33 }
34
35
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 0xFF.
39
40    The Display and Visual arguments are used only for creating the XImage;
41    no bits are pushed to the server.
42
43    The Colormap argument is used just for parsing color names; no colors
44    are allocated.
45  */
46 XImage *
47 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap, char **xpm_data)
48 {
49   /* All we want to do is get RGB data out of the XPM file built in to this
50      program.  This is a pain, because there is no way  (as of XPM version
51      4.6, at least) to get libXpm to make an XImage without also allocating
52      colors with XAllocColor.  So, instead, we create an XpmImage and parse
53      out the RGB values of the pixels ourselves; and construct an XImage
54      by hand.  Regardless of the depth of the visual we're using, this
55      XImage will have 32 bits per pixel, 8 each per R, G, and B.  We put
56      0xFF in the fourth slot, as GL will interpret that as "alpha".
57    */
58   XImage *ximage = 0;
59   XpmImage xpm_image;
60   XpmInfo xpm_info;
61   int result;
62   int x, y, i;
63   int bpl, wpl;
64   XColor colors[255];
65
66   result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
67   if (result != XpmSuccess)
68     {
69       fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
70               result);
71       exit (1);
72     }
73
74   ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
75                          xpm_image.width, xpm_image.height, 32, 0);
76
77   bpl = ximage->bytes_per_line;
78   wpl = bpl/4;
79
80   ximage->data = (char *) malloc(xpm_image.height * bpl);
81
82   /* Parse the colors in the XPM into RGB values. */
83   for (i = 0; i < xpm_image.ncolors; i++)
84     if (!XParseColor(dpy, cmap, xpm_image.colorTable[i].c_color, &colors[i]))
85       {
86         fprintf(stderr, "%s: unparsable color: %s\n", progname,
87                 xpm_image.colorTable[i].c_color);
88         exit(1);
89       }
90
91   /* Translate the XpmImage to an RGB XImage. */
92   {
93     int rpos, gpos, bpos, apos;  /* bitfield positions */
94
95     /* Note that unlike X, which is endianness-agnostic (since any XImage
96        can have its own specific bit ordering, with the server reversing
97        things as necessary) OpenGL pretends everything is client-side, so
98        we need to pack things in the right order for the client machine.
99      */
100     if (bigendian())
101       rpos = 24, gpos = 16, bpos =  8, apos =  0;
102     else
103       rpos =  0, gpos =  8, bpos = 16, apos = 24;
104
105     for (y = 0; y < xpm_image.height; y++)
106       {
107         int y2 = (xpm_image.height-1-y); /* Texture maps are upside down. */
108
109         unsigned int *oline = (unsigned int *) (ximage->data   + (y  * bpl));
110         unsigned int *iline = (unsigned int *) (xpm_image.data + (y2 * wpl));
111
112         for (x = 0; x < xpm_image.width; x++)
113           {
114             XColor *c = &colors[iline[x]];
115             /* pack it as RGBA */
116             oline[x] = (((c->red   >> 8) << rpos) |
117                         ((c->green >> 8) << gpos) |
118                         ((c->blue  >> 8) << bpos) |
119                         (0xFF            << apos));
120           }
121       }
122   }
123
124   /* I sure hope these only free the contents, and not the args. */
125   XpmFreeXpmImage (&xpm_image);
126   XpmFreeXpmInfo (&xpm_info);
127
128   return ximage;
129 }
130
131
132 #else  /* !HAVE_XPM */
133
134 static XImage *
135 xpm_to_ximage (char **xpm_data)
136 {
137   fprintf(stderr, "%s: not compiled with XPM support.\n", progname);
138   exit (1);
139 }
140
141 #endif /* !HAVE_XPM */