+ if (colors) free (colors);
+
+ return to;
+}
+
+#endif /* REFORMAT_IMAGE_DATA */
+
+/* Shrinks the XImage by a factor of two.
+ We use this when mipmapping fails on large textures.
+ */
+static void
+halve_image (XImage *ximage, XRectangle *geom)
+{
+ int w2 = ximage->width/2;
+ int h2 = ximage->height/2;
+ int x, y;
+ XImage *ximage2;
+
+ if (w2 <= 32 || h2 <= 32) /* let's not go crazy here, man. */
+ return;
+
+ if (debug_p)
+ fprintf (stderr, "%s: shrinking image %dx%d -> %dx%d\n",
+ progname, ximage->width, ximage->height, w2, h2);
+
+ ximage2 = (XImage *) calloc (1, sizeof (*ximage2));
+ *ximage2 = *ximage;
+ ximage2->width = w2;
+ ximage2->height = h2;
+ ximage2->bytes_per_line = 0;
+ ximage2->data = 0;
+ XInitImage (ximage2);
+
+ ximage2->data = (char *) calloc (h2, ximage2->bytes_per_line);
+ if (!ximage2->data)
+ {
+ fprintf (stderr, "%s: out of memory (scaling %dx%d image to %dx%d)\n",
+ progname, ximage->width, ximage->height, w2, h2);
+ exit (1);
+ }
+
+ for (y = 0; y < h2; y++)
+ for (x = 0; x < w2; x++)
+ XPutPixel (ximage2, x, y, XGetPixel (ximage, x*2, y*2));
+
+ free (ximage->data);
+ *ximage = *ximage2;
+ ximage2->data = 0;
+ XFree (ximage2);
+
+ if (geom)
+ {
+ geom->x /= 2;
+ geom->y /= 2;
+ geom->width /= 2;
+ geom->height /= 2;
+ }
+}
+
+
+#ifdef REFORMAT_IMAGE_DATA
+
+/* Pulls the Pixmap bits from the server and returns an XImage
+ in some format acceptable to OpenGL.
+ */
+static XImage *
+pixmap_to_gl_ximage (Screen *screen, Window window, Pixmap pixmap)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ unsigned int width, height, depth;
+
+# ifdef HAVE_XSHM_EXTENSION
+ Bool use_shm = get_boolean_resource (dpy, "useSHM", "Boolean");
+ XShmSegmentInfo shm_info;
+# endif /* HAVE_XSHM_EXTENSION */
+
+ XImage *server_ximage = 0;
+ XImage *client_ximage = 0;
+
+ {
+ Window root;
+ int x, y;
+ unsigned int bw;
+ XGetGeometry (dpy, pixmap, &root, &x, &y, &width, &height, &bw, &depth);
+ }
+
+ if (width < 5 || height < 5) /* something's gone wrong somewhere... */
+ return 0;
+
+ /* Convert the server-side Pixmap to a client-side GL-ordered XImage.
+ */
+# ifdef HAVE_XSHM_EXTENSION
+ if (use_shm)
+ {
+ Visual *visual = DefaultVisualOfScreen (screen);
+ server_ximage = create_xshm_image (dpy, visual, depth,
+ ZPixmap, 0, &shm_info,
+ width, height);
+ if (server_ximage)
+ XShmGetImage (dpy, pixmap, server_ximage, 0, 0, ~0L);
+ else
+ use_shm = False;
+ }
+# endif /* HAVE_XSHM_EXTENSION */
+
+ if (!server_ximage)
+ server_ximage = XGetImage (dpy, pixmap, 0, 0, width, height, ~0L, ZPixmap);
+
+ client_ximage = convert_ximage_to_rgba32 (screen, server_ximage);
+
+# ifdef HAVE_XSHM_EXTENSION
+ if (use_shm)
+ destroy_xshm_image (dpy, server_ximage, &shm_info);
+ else
+# endif /* HAVE_XSHM_EXTENSION */
+ XDestroyImage (server_ximage);
+
+ return client_ximage;
+}
+
+
+# else /* ! REFORMAT_IMAGE_DATA */
+
+typedef struct {
+ unsigned int depth, red_mask, green_mask, blue_mask; /* when this... */
+ GLint type, format; /* ...use this. */
+} conversion_table;
+
+/* Abbreviate these so that the table entries all fit on one line...
+ */
+#define BYTE GL_UNSIGNED_BYTE
+#define BYTE_2_3_3_REV GL_UNSIGNED_BYTE_2_3_3_REV
+#define BYTE_3_3_2 GL_UNSIGNED_BYTE_3_3_2
+#define INT_10_10_10_2 GL_UNSIGNED_INT_10_10_10_2
+#define INT_2_10_10_10_REV GL_UNSIGNED_INT_2_10_10_10_REV
+#define INT_8_8_8_8 GL_UNSIGNED_INT_8_8_8_8
+#define INT_8_8_8_8_REV GL_UNSIGNED_INT_8_8_8_8_REV
+#define SHORT_1_5_5_5_REV GL_UNSIGNED_SHORT_1_5_5_5_REV
+#define SHORT_4_4_4_4 GL_UNSIGNED_SHORT_4_4_4_4
+#define SHORT_4_4_4_4_REV GL_UNSIGNED_SHORT_4_4_4_4_REV
+#define SHORT_5_5_5_1 GL_UNSIGNED_SHORT_5_5_5_1
+#define SHORT_5_6_5 GL_UNSIGNED_SHORT_5_6_5
+#define SHORT_5_6_5_REV GL_UNSIGNED_SHORT_5_6_5_REV
+
+static const conversion_table ctable[] = {
+ { 8, 0x000000E0, 0x0000001C, 0x00000003, BYTE_3_3_2, GL_RGB },
+ { 8, 0x00000007, 0x00000038, 0x000000C0, BYTE_2_3_3_REV, GL_RGB },
+ { 16, 0x0000F800, 0x000007E0, 0x0000001F, SHORT_5_6_5, GL_RGB },
+ { 16, 0x0000001F, 0x000007E0, 0x0000F800, SHORT_5_6_5_REV, GL_RGB },
+ { 16, 0x0000F000, 0x00000F00, 0x000000F0, SHORT_4_4_4_4, GL_RGBA },
+ { 16, 0x000000F0, 0x00000F00, 0x0000F000, SHORT_4_4_4_4, GL_BGRA },
+ { 16, 0x0000000F, 0x000000F0, 0x00000F00, SHORT_4_4_4_4, GL_ABGR_EXT },
+ { 16, 0x0000000F, 0x000000F0, 0x00000F00, SHORT_4_4_4_4_REV, GL_RGBA },
+ { 16, 0x00000F00, 0x000000F0, 0x0000000F, SHORT_4_4_4_4_REV, GL_BGRA },
+ { 16, 0x0000F800, 0x000007C0, 0x0000003E, SHORT_5_5_5_1, GL_RGBA },
+ { 16, 0x0000003E, 0x000007C0, 0x0000F800, SHORT_5_5_5_1, GL_BGRA },
+ { 16, 0x00000001, 0x0000003E, 0x000007C0, SHORT_5_5_5_1, GL_ABGR_EXT },
+ { 16, 0x0000001F, 0x000003E0, 0x00007C00, SHORT_1_5_5_5_REV, GL_RGBA },
+ { 16, 0x00007C00, 0x000003E0, 0x0000001F, SHORT_1_5_5_5_REV, GL_BGRA },
+ { 32, 0xFF000000, 0x00FF0000, 0x0000FF00, INT_8_8_8_8, GL_RGBA },
+ { 32, 0x0000FF00, 0x00FF0000, 0xFF000000, INT_8_8_8_8, GL_BGRA },
+ { 32, 0x000000FF, 0x0000FF00, 0x00FF0000, INT_8_8_8_8, GL_ABGR_EXT },
+ { 32, 0x000000FF, 0x0000FF00, 0x00FF0000, INT_8_8_8_8_REV, GL_RGBA },
+ { 32, 0x00FF0000, 0x0000FF00, 0x000000FF, INT_8_8_8_8_REV, GL_BGRA },
+ { 32, 0xFFC00000, 0x003FF000, 0x00000FFC, INT_10_10_10_2, GL_RGBA },
+ { 32, 0x00000FFC, 0x003FF000, 0xFFC00000, INT_10_10_10_2, GL_BGRA },
+ { 32, 0x00000003, 0x00000FFC, 0x003FF000, INT_10_10_10_2, GL_ABGR_EXT },
+ { 32, 0x000003FF, 0x000FFC00, 0x3FF00000, INT_2_10_10_10_REV, GL_RGBA },
+ { 32, 0x3FF00000, 0x000FFC00, 0x000003FF, INT_2_10_10_10_REV, GL_BGRA },
+ { 24, 0x000000FF, 0x0000FF00, 0x00FF0000, BYTE, GL_RGB },
+ { 24, 0x00FF0000, 0x0000FF00, 0x000000FF, BYTE, GL_BGR },
+};
+
+
+/* Given an XImage, returns the GL settings to use its data as a texture.
+ */
+static void
+gl_settings_for_ximage (XImage *image,
+ GLint *type_ret, GLint *format_ret, GLint *swap_ret)
+{
+ int i;
+ for (i = 0; i < countof(ctable); ++i)
+ {
+ if (image->bits_per_pixel == ctable[i].depth &&
+ image->red_mask == ctable[i].red_mask &&
+ image->green_mask == ctable[i].green_mask &&
+ image->blue_mask == ctable[i].blue_mask)