1 /* grab-ximage.c --- grab the screen to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 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
20 #include <X11/Xutil.h>
21 #include <GL/gl.h> /* only for GLfloat */
23 #include "grabscreen.h"
25 extern char *progname;
27 #include <X11/Xutil.h>
30 #define MAX(a,b) ((a)>(b)?(a):(b))
33 #define countof(x) (sizeof((x))/sizeof((*x)))
38 union { int i; char c[sizeof(int)]; } u;
43 /* return the next larger power of 2. */
47 static unsigned int pow2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
48 2048, 4096, 8192, 16384, 32768, 65536 };
50 for (j = 0; j < countof(pow2); j++)
51 if (pow2[j] >= i) return pow2[j];
52 abort(); /* too big! */
56 /* Returns an XImage structure containing an image of the desktop.
57 (As a side-effect, that image will be painted onto the given Window.)
58 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
59 extra byte set to 0xFF.
62 screen_to_ximage (Screen *screen, Window window)
64 Display *dpy = DisplayOfScreen (screen);
65 XWindowAttributes xgwa;
66 int win_width, win_height;
67 int tex_width, tex_height;
69 grab_screen_image (screen, window);
71 XGetWindowAttributes (dpy, window, &xgwa);
72 win_width = xgwa.width;
73 win_height = xgwa.height;
75 /* GL texture sizes must be powers of two. */
76 tex_width = to_pow2(win_width);
77 tex_height = to_pow2(win_height);
79 /* Convert the server-side Drawable to a client-side GL-ordered XImage.
82 XImage *ximage1, *ximage2;
84 ximage1 = XGetImage (dpy, window, 0, 0, win_width, win_height, ~0L,
86 ximage2 = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
87 tex_width, tex_height, 32, 0);
89 ximage2->data = (char *) calloc (tex_height, ximage2->bytes_per_line);
91 /* Translate the server-ordered image to a client-ordered image.
95 int crpos, cgpos, cbpos, capos; /* bitfield positions */
96 int srpos, sgpos, sbpos;
97 int srmsk, sgmsk, sbmsk;
98 int sdepth = ximage1->depth;
100 srmsk = ximage1->red_mask;
101 sgmsk = ximage1->green_mask;
102 sbmsk = ximage1->blue_mask;
103 if (sdepth == 32 || sdepth == 24)
104 srpos = 16, sgpos = 8, sbpos = 0;
106 srpos = 10, sgpos = 5, sbpos = 0;
108 /* Note that unlike X, which is endianness-agnostic (since any XImage
109 can have its own specific bit ordering, with the server reversing
110 things as necessary) OpenGL pretends everything is client-side, so
111 we need to pack things in the right order for the client machine.
114 crpos = 24, cgpos = 16, cbpos = 8, capos = 0;
116 crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
118 for (y = 0; y < win_height; y++)
120 int y2 = (win_height-1-y); /* Texture maps are upside down. */
121 for (x = 0; x < win_width; x++)
123 unsigned long sp = XGetPixel (ximage1, x, y2);
124 unsigned char sr = (sp & srmsk) >> srpos;
125 unsigned char sg = (sp & sgmsk) >> sgpos;
126 unsigned char sb = (sp & sbmsk) >> sbpos;
129 if (sdepth < 24) /* spread 5 bits to 8 */
131 sr = (sr << 3) | (sr >> 2);
132 sg = (sg << 3) | (sg >> 2);
133 sb = (sb << 3) | (sb >> 2);
135 cp = ((sr << crpos) |
139 XPutPixel (ximage2, x, y, cp);
144 free (ximage1->data);
146 XDestroyImage (ximage1);
149 fprintf(stderr, "%s: grabbed %dx%d window 0x%lx to %dx%d texture\n",
150 progname, win_width, win_height, (unsigned long) window,
151 tex_width, tex_height);