New glxsnoop demo to display another window's z/stencil/back buffer.
This commit is contained in:
parent
f05c76ec1a
commit
f1104b079f
|
@ -17,6 +17,7 @@ PROGS = glthreads \
|
|||
glxinfo \
|
||||
glxpixmap \
|
||||
glxpbdemo \
|
||||
glxsnoop \
|
||||
glxswapcontrol \
|
||||
manywin \
|
||||
offset \
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
/**
|
||||
* Display/snoop the z/stencil/back/front buffers of another app's window.
|
||||
* Also, an example of the need for shared ancillary renderbuffers.
|
||||
*
|
||||
* Hint: use 'xwininfo' to get a window's ID.
|
||||
*
|
||||
* Brian Paul
|
||||
* 11 Oct 2007
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
|
||||
#define Z_BUFFER 1
|
||||
#define STENCIL_BUFFER 2
|
||||
#define BACK_BUFFER 3
|
||||
#define FRONT_BUFFER 4
|
||||
|
||||
|
||||
static int Buffer = BACK_BUFFER;
|
||||
static int WindowID = 0;
|
||||
static const char *DisplayName = NULL;
|
||||
static GLXContext Context = 0;
|
||||
static int Width, Height;
|
||||
|
||||
|
||||
/**
|
||||
* Grab the z/stencil/back/front image from the srcWin and display it
|
||||
* (possibly converted to grayscale) in the dstWin.
|
||||
*/
|
||||
static void
|
||||
redraw(Display *dpy, Window srcWin, Window dstWin )
|
||||
{
|
||||
GLubyte *image = malloc(Width * Height * 4);
|
||||
|
||||
glXMakeCurrent(dpy, srcWin, Context);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
if (Buffer == BACK_BUFFER) {
|
||||
glReadBuffer(GL_BACK);
|
||||
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
}
|
||||
else if (Buffer == FRONT_BUFFER) {
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
}
|
||||
else if (Buffer == Z_BUFFER) {
|
||||
GLfloat *z = malloc(Width * Height * sizeof(GLfloat));
|
||||
int i;
|
||||
glReadPixels(0, 0, Width, Height, GL_DEPTH_COMPONENT, GL_FLOAT, z);
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
image[i*4+0] =
|
||||
image[i*4+1] =
|
||||
image[i*4+2] = (GLint) (255.0 * z[i]);
|
||||
image[i*4+3] = 255;
|
||||
}
|
||||
free(z);
|
||||
}
|
||||
else if (Buffer == STENCIL_BUFFER) {
|
||||
GLubyte *sten = malloc(Width * Height * sizeof(GLubyte));
|
||||
int i, min = 100, max = -1;
|
||||
float step;
|
||||
int sz;
|
||||
glGetIntegerv(GL_STENCIL_BITS, &sz);
|
||||
glReadPixels(0, 0, Width, Height,
|
||||
GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, sten);
|
||||
/* find min/max for converting stencil to grayscale */
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
if (sten[i] < min)
|
||||
min = sten[i];
|
||||
if (sten[i] > max)
|
||||
max = sten[i];
|
||||
}
|
||||
if (min == max)
|
||||
step = 0;
|
||||
else
|
||||
step = 255.0 / (float) (max - min);
|
||||
for (i = 0; i < Width * Height; i++) {
|
||||
image[i*4+0] =
|
||||
image[i*4+1] =
|
||||
image[i*4+2] = (GLint) ((sten[i] - min) * step);
|
||||
image[i*4+3] = 255;
|
||||
}
|
||||
free(sten);
|
||||
}
|
||||
|
||||
glXMakeCurrent(dpy, dstWin, Context);
|
||||
glWindowPos2iARB(0, 0);
|
||||
glDrawBuffer(GL_FRONT);
|
||||
glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
glFlush();
|
||||
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_window_title(Display *dpy, Window win, const char *title)
|
||||
{
|
||||
XSizeHints sizehints;
|
||||
sizehints.flags = 0;
|
||||
XSetStandardProperties(dpy, win, title, title,
|
||||
None, (char **)NULL, 0, &sizehints);
|
||||
}
|
||||
|
||||
|
||||
static Window
|
||||
make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
|
||||
{
|
||||
int scrnum;
|
||||
XSetWindowAttributes attr;
|
||||
unsigned long mask;
|
||||
Window root;
|
||||
Window win;
|
||||
int x = 0, y = 0;
|
||||
char *name = NULL;
|
||||
|
||||
scrnum = DefaultScreen( dpy );
|
||||
root = RootWindow( dpy, scrnum );
|
||||
|
||||
/* window attributes */
|
||||
attr.background_pixel = 0;
|
||||
attr.border_pixel = 0;
|
||||
attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
|
||||
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
|
||||
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
|
||||
|
||||
win = XCreateWindow( dpy, root, x, y, width, height,
|
||||
0, visinfo->depth, InputOutput,
|
||||
visinfo->visual, mask, &attr );
|
||||
|
||||
/* set hints and properties */
|
||||
{
|
||||
XSizeHints sizehints;
|
||||
sizehints.x = x;
|
||||
sizehints.y = y;
|
||||
sizehints.width = width;
|
||||
sizehints.height = height;
|
||||
sizehints.flags = USSize | USPosition;
|
||||
XSetNormalHints(dpy, win, &sizehints);
|
||||
XSetStandardProperties(dpy, win, name, name,
|
||||
None, (char **)NULL, 0, &sizehints);
|
||||
}
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
update_window_title(Display *dpy, Window win)
|
||||
{
|
||||
char title[1000], *buf;
|
||||
|
||||
switch (Buffer) {
|
||||
case Z_BUFFER:
|
||||
buf = "Z";
|
||||
break;
|
||||
case STENCIL_BUFFER:
|
||||
buf = "Stencil";
|
||||
break;
|
||||
case BACK_BUFFER:
|
||||
buf = "Back";
|
||||
break;
|
||||
case FRONT_BUFFER:
|
||||
buf = "Front";
|
||||
break;
|
||||
default:
|
||||
buf = "";
|
||||
}
|
||||
|
||||
sprintf(title, "glxsnoop window 0x%x (%s buffer)", (int) WindowID, buf);
|
||||
|
||||
set_window_title(dpy, win, title);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
keypress(Display *dpy, Window win, char key)
|
||||
{
|
||||
switch (key) {
|
||||
case 27:
|
||||
/* escape */
|
||||
exit(0);
|
||||
break;
|
||||
case 's':
|
||||
Buffer = STENCIL_BUFFER;
|
||||
break;
|
||||
case 'z':
|
||||
Buffer = Z_BUFFER;
|
||||
break;
|
||||
case 'f':
|
||||
Buffer = FRONT_BUFFER;
|
||||
break;
|
||||
case 'b':
|
||||
Buffer = BACK_BUFFER;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
update_window_title(dpy, win);
|
||||
redraw(dpy, WindowID, win);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
event_loop(Display *dpy, Window win)
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
while (1) {
|
||||
XNextEvent( dpy, &event );
|
||||
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
redraw(dpy, WindowID, win);
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
/*resize( event.xconfigure.width, event.xconfigure.height );*/
|
||||
break;
|
||||
case KeyPress:
|
||||
{
|
||||
char buffer[10];
|
||||
int r, code;
|
||||
code = XLookupKeysym(&event.xkey, 0);
|
||||
if (code == XK_Left) {
|
||||
}
|
||||
else {
|
||||
r = XLookupString(&event.xkey, buffer, sizeof(buffer),
|
||||
NULL, NULL);
|
||||
keypress(dpy, win, buffer[0]);
|
||||
}
|
||||
}
|
||||
default:
|
||||
/* nothing */
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static VisualID
|
||||
get_window_visualid(Display *dpy, Window win)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
|
||||
if (XGetWindowAttributes(dpy, win, &attr)) {
|
||||
return attr.visual->visualid;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_window_size(Display *dpy, Window win, int *w, int *h)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
|
||||
if (XGetWindowAttributes(dpy, win, &attr)) {
|
||||
*w = attr.width;
|
||||
*h = attr.height;
|
||||
}
|
||||
else {
|
||||
*w = *h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static XVisualInfo *
|
||||
visualid_to_visualinfo(Display *dpy, VisualID vid)
|
||||
{
|
||||
XVisualInfo *vinfo, templ;
|
||||
long mask;
|
||||
int n;
|
||||
|
||||
templ.visualid = vid;
|
||||
mask = VisualIDMask;
|
||||
|
||||
vinfo = XGetVisualInfo(dpy, mask, &templ, &n);
|
||||
return vinfo;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
key_usage(void)
|
||||
{
|
||||
printf("Keyboard:\n");
|
||||
printf(" z - display Z buffer\n");
|
||||
printf(" s - display stencil buffer\n");
|
||||
printf(" f - display front color buffer\n");
|
||||
printf(" b - display back buffer\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: glxsnoop [-display dpy] windowID\n");
|
||||
key_usage();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parse_opts(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
usage();
|
||||
exit(0);
|
||||
}
|
||||
else if (strcmp(argv[i], "-display") == 0) {
|
||||
DisplayName = argv[i + 1];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
if (argv[i][0] == '0' && argv[i][1] == 'x') {
|
||||
/* hex */
|
||||
WindowID = strtol(argv[i], NULL, 16);
|
||||
}
|
||||
else {
|
||||
WindowID = atoi(argv[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WindowID) {
|
||||
usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main( int argc, char *argv[] )
|
||||
{
|
||||
Display *dpy;
|
||||
VisualID vid;
|
||||
XVisualInfo *visinfo;
|
||||
Window win;
|
||||
|
||||
parse_opts(argc, argv);
|
||||
|
||||
key_usage();
|
||||
|
||||
dpy = XOpenDisplay(DisplayName);
|
||||
|
||||
/* find the VisualID for the named window */
|
||||
vid = get_window_visualid(dpy, WindowID);
|
||||
get_window_size(dpy, WindowID, &Width, &Height);
|
||||
|
||||
visinfo = visualid_to_visualinfo(dpy, vid);
|
||||
|
||||
Context = glXCreateContext( dpy, visinfo, NULL, True );
|
||||
if (!Context) {
|
||||
printf("Error: glXCreateContext failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
win = make_gl_window(dpy, visinfo, Width, Height);
|
||||
XMapWindow(dpy, win);
|
||||
update_window_title(dpy, win);
|
||||
|
||||
event_loop( dpy, win );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue