Dark Photon
06-28-2012, 06:16 PM
I want to learn how I'd do that without using "glut", that my main issue.
To save yourself trouble, you probably want to use GLUT or some other helper library (and yes, freeglut and a number of others are out there on Linux).
But if you really do want the bare-bones "how do you do it with just plain X11 and GL", here you go:
Two examples: One with new-style context creation and one with old-style.
New-style GL context:
//------------------------------------------------------------------------------
// glx_simple_new - Shows how to create an X window and a new-style
// GL context without GLUT or any helper libraries.
//
// COMPILE WITH:
// g++ -g -o glx_simple_new glx_simple_new.cxx -lGLU -lGL -lX11
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
struct MyWin
{
Display *display;
Window win;
bool displayed;
int width;
int height;
};
//----------------------------------------------------------------------------
const int WIN_XPOS = 256;
const int WIN_YPOS = 64;
const int WIN_XRES = 320;
const int WIN_YRES = 320;
const int NUM_SAMPLES = 4;
//----------------------------------------------------------------------------
MyWin Win;
//----------------------------------------------------------------------------
double elapsedMsec( const struct timeval &start, const struct timeval &stop )
{
return ( ( stop.tv_sec - start.tv_sec ) * 1000.0 +
( stop.tv_usec - start.tv_usec ) / 1000.0 );
}
//----------------------------------------------------------------------------
double elapsedUsec( const struct timeval &start, const struct timeval &stop )
{
return ( ( stop.tv_sec - start.tv_sec ) * 1000000.0 +
( stop.tv_usec - start.tv_usec ) );
}
//-----------------------------------------------------------------------------
/// check() - Check for GL errors, and report any queued
void check( const char hdr[] = "" )
{
int err;
while ( ( err = glGetError() ) != GL_NO_ERROR )
fprintf( stderr, "OpenGL Error at %s: %s\n", hdr, gluErrorString(err) );
}
//----------------------------------------------------------------------------
void displayCB()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//---------------------------------------------------
// FIXME: Insert GL draw code here
//---------------------------------------------------
// Display it
glXSwapBuffers( Win.display, Win.win );
check( "displayCB()" );
}
//----------------------------------------------------------------------------
void keyboardCB( KeySym sym, unsigned char key, int x, int y,
bool &setting_change )
{
switch ( tolower( key ) )
{
case 27:
// ESCape - We're done!
exit (0);
break;
case 'k':
printf( "You hit the 'k' key\n" );
break;
case 0:
switch ( sym )
{
case XK_Left :
printf( "You hit the Left Arrow key\n" );
break;
case XK_Right :
printf( "You hit the Right Arrow key\n" );
break;
}
break;
}
}
//----------------------------------------------------------------------------
void reshapeCB( int width, int height )
{
Win.width = width;
Win.height = height;
}
//----------------------------------------------------------------------------
/** chooseFBConfig() - Try to find a framebuffer config that matches
* the specified pixel requirements.
*/
GLXFBConfig chooseFBConfig( Display *display, int screen )
{
// Default template
static const int Visual_attribs[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
GLX_SAMPLE_BUFFERS , 1,
GLX_SAMPLES , 4,
None
};
int attribs [ 100 ] ;
memcpy( attribs, Visual_attribs, sizeof( Visual_attribs ) );
// DELETED
GLXFBConfig ret = 0;
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig( display, screen,
attribs, &fbcount );
if ( fbc )
{
if ( fbcount >= 1 )
ret = fbc[0];
XFree( fbc );
}
return ret;
}
//----------------------------------------------------------------------------
GLXContext createContext( Display *display, int screen,
GLXFBConfig fbconfig, XVisualInfo *visinfo,
Window window )
{
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
// Verify GL driver supports glXCreateContextAttribsARB()
// Create an old-style GLX context first, to get the correct function ptr.
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
GLXContext ctx_old = glXCreateContext( display, visinfo, 0, True );
if ( !ctx_old )
{
printf( "Could not even allocate an old-style GL context!\n" );
exit(1);
}
glXMakeCurrent ( display, window, ctx_old ) ;
// Verify that GLX implementation supports the new context create call
if ( strstr( glXQueryExtensionsString( display, screen ),
"GLX_ARB_create_context" ) != 0 )
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddress( (const GLubyte *) "glXCreateContextAttribsARB" );
if ( !glXCreateContextAttribsARB )
{
printf( "Can't create new-style GL context\n" );
exit(1);
}
// Got the pointer. Nuke old context.
glXMakeCurrent( display, None, 0 );
glXDestroyContext( display, ctx_old );
// Try to allocate a GL 4.2 COMPATIBILITY context
static int Context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
//GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB,
None
};
GLXContext context = glXCreateContextAttribsARB( display, fbconfig, 0,
True, Context_attribs );
// Forcably wait on any resulting X errors
XSync( display, False );
if ( !context )
{
printf( "Failed to allocate a GL 4.2 context\n" );
exit(1);
}
printf( "Created GL 4.2 context\n" );
return context;
}
//----------------------------------------------------------------------------
void createWindow()
{
// Init X and GLX
Win.displayed = false;
Display *display = Win.display = XOpenDisplay( ":0.0" );
if ( !display )
printf( "Cannot open X display\n" );
int screen = DefaultScreen( display );
Window root_win = RootWindow( display, screen );
if ( !glXQueryExtension( display, 0, 0 ) )
printf( "X Server doesn't support GLX extension\n" );
// Pick an FBconfig and visual
GLXFBConfig fbconfig = chooseFBConfig( display, screen );
if ( !fbconfig )
{
printf( "Failed to get GLXFBConfig\n" );
exit(1);
}
XVisualInfo *visinfo = glXGetVisualFromFBConfig( display, fbconfig );
if ( !visinfo )
{
printf( "Failed to get XVisualInfo\n" );
exit(1);
}
printf( "X Visual ID = 0x%.2x\n", int( visinfo->visualid ) );
// Create the X window
XSetWindowAttributes winAttr ;
winAttr.event_mask = StructureNotifyMask | KeyPressMask ;
winAttr.background_pixmap = None ;
winAttr.background_pixel = 0 ;
winAttr.border_pixel = 0 ;
winAttr.colormap = XCreateColormap( display, root_win,
visinfo->visual, AllocNone );
unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
Window win = Win.win = XCreateWindow ( display, root_win,
WIN_XPOS, WIN_YPOS,
WIN_XRES, WIN_YRES, 0,
visinfo->depth, InputOutput,
visinfo->visual, mask, &winAttr ) ;
XStoreName( Win.display, win, "My GLX Window");
// Create an OpenGL context and attach it to our X window
GLXContext context = createContext( display, screen, fbconfig, visinfo, win );
if ( ! glXMakeCurrent( display, win, context ) )
printf( "glXMakeCurrent failed.\n" );
if ( ! glXIsDirect ( display, glXGetCurrentContext() ) )
printf( "Indirect GLX rendering context obtained\n" );
// Display the window
XMapWindow( display, win );
if ( ! glXMakeCurrent( display, win, context ) )
printf( "glXMakeCurrent failed.\n" );
check( "createWindow()" );
printf( "Window Size = %d x %d\n", WIN_XRES, WIN_YRES );
printf( "Window Samples = %d\n", NUM_SAMPLES );
}
//----------------------------------------------------------------------------
void processXEvents( Atom wm_protocols, Atom wm_delete_window )
{
bool setting_change = false;
while ( XEventsQueued( Win.display, QueuedAfterFlush ) )
{
XEvent event;
XNextEvent( Win.display, &event );
if( event.xany.window != Win.win )
continue;
switch ( event.type )
{
case MapNotify:
{
Win.displayed = true;
break;
}
case ConfigureNotify:
{
XConfigureEvent &cevent = event.xconfigure;
reshapeCB( cevent.width, cevent.height );
break;
}
case KeyPress:
{
char chr;
KeySym symbol;
XComposeStatus status;
XLookupString( &event.xkey, &chr, 1, &symbol, &status );
keyboardCB( symbol, chr, event.xkey.x, event.xkey.y,
setting_change );
break;
}
case ClientMessage:
{
if ( event.xclient.message_type == wm_protocols &&
Atom( event.xclient.data.l[0] ) == wm_delete_window )
{
//printf( "Received WM_DELETE_WINDOW\n" );
exit(0);
}
break;
}
}
}
}
//----------------------------------------------------------------------------
void mainLoop()
{
// Register to receive window close events (the "X" window manager button)
Atom wm_protocols = XInternAtom( Win.display, "WM_PROTOCOLS" , False);
Atom wm_delete_window = XInternAtom( Win.display, "WM_DELETE_WINDOW", False);
XSetWMProtocols( Win.display, Win.win, &wm_delete_window, True );
while (1)
{
// Redraw window (after it's mapped)
if ( Win.displayed )
displayCB();
// Update frame rate
static timeval last_xcheck = {0,0};
struct timeval now;
gettimeofday( &now, 0 );
// Check X events every 1/10 second
if ( elapsedMsec( last_xcheck, now ) > 100 )
{
processXEvents( wm_protocols, wm_delete_window );
last_xcheck = now;
}
}
}
//----------------------------------------------------------------------------
int main( int argc, char *argv[] )
{
// Init globals
Win.width = WIN_XRES, Win.height = WIN_YRES;
// Create context and window
createWindow();
// Init OpenGL
glViewport ( 0, 0, Win.width, Win.height );
glColorMask ( 1,1,1,1 );
glClearColor( 0,0,1,1 );
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Go
printf( "Valid keys: Left, Right, k, ESC\n" );
printf( "Press ESC to quit\n" );
mainLoop();
return 0;
}
And old-style GL context:
//------------------------------------------------------------------------------
// glx_simple_old - Shows how to create an X window and a old-style
// GL context without GLUT or any helper libraries.
//
// COMPILE WITH:
// g++ -g -o glx_simple_old glx_simple_old.cxx -lGLU -lGL -lX11
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
struct MyWin
{
Display *display;
Window win;
bool displayed;
int width;
int height;
};
//----------------------------------------------------------------------------
const int WIN_XPOS = 256;
const int WIN_YPOS = 64;
const int WIN_XRES = 320;
const int WIN_YRES = 320;
const int NUM_SAMPLES = 4;
//----------------------------------------------------------------------------
MyWin Win;
//----------------------------------------------------------------------------
double elapsedMsec( const struct timeval &start, const struct timeval &stop )
{
return ( ( stop.tv_sec - start.tv_sec ) * 1000.0 +
( stop.tv_usec - start.tv_usec ) / 1000.0 );
}
//----------------------------------------------------------------------------
double elapsedUsec( const struct timeval &start, const struct timeval &stop )
{
return ( ( stop.tv_sec - start.tv_sec ) * 1000000.0 +
( stop.tv_usec - start.tv_usec ) );
}
//-----------------------------------------------------------------------------
/// check() - Check for GL errors, and report any queued
void check( const char hdr[] = "" )
{
int err;
while ( ( err = glGetError() ) != GL_NO_ERROR )
fprintf( stderr, "OpenGL Error at %s: %s\n", hdr, gluErrorString(err) );
}
//----------------------------------------------------------------------------
void displayCB()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//---------------------------------------------------
// FIXME: Insert GL draw code here
//---------------------------------------------------
// Display it
glXSwapBuffers( Win.display, Win.win );
check( "displayCB()" );
}
//----------------------------------------------------------------------------
void keyboardCB( KeySym sym, unsigned char key, int x, int y,
bool &setting_change )
{
switch ( tolower( key ) )
{
case 27:
// ESCape - We're done!
exit (0);
break;
case 'k':
printf( "You hit the 'k' key\n" );
break;
case 0:
switch ( sym )
{
case XK_Left :
printf( "You hit the Left Arrow key\n" );
break;
case XK_Right :
printf( "You hit the Right Arrow key\n" );
break;
}
break;
}
}
//----------------------------------------------------------------------------
void reshapeCB( int width, int height )
{
Win.width = width;
Win.height = height;
}
//----------------------------------------------------------------------------
XVisualInfo *chooseVisual( Display *display )
{
int attribs [ 100 ] ;
int n = 0 ;
// Request 24-bit color with alpha
attribs [n++] = GLX_RGBA ;
attribs [n++] = GLX_RED_SIZE ; attribs [n++] = 8 ;
attribs [n++] = GLX_GREEN_SIZE ; attribs [n++] = 8 ;
attribs [n++] = GLX_BLUE_SIZE ; attribs [n++] = 8 ;
// Request 24-bit depth buffer
attribs [n++] = GLX_DEPTH_SIZE ; attribs [n++] = 24 ;
// Request 4 multisamples per pixel
attribs [n++] = GLX_SAMPLE_BUFFERS ; attribs [n++] = 1 ;
attribs [n++] = GLX_SAMPLES ; attribs [n++] = NUM_SAMPLES ;
// Request double-buffering
attribs [n++] = GLX_DOUBLEBUFFER ;
attribs [n++] = None ;
return glXChooseVisual( display, DefaultScreen( display ), attribs );
}
//----------------------------------------------------------------------------
void createWindow()
{
// Init X and GLX
Win.displayed = false;
Display *display = Win.display = XOpenDisplay( ":0.0" );
if ( !display )
printf( "Cannot open X display\n" );
int screen = DefaultScreen( display );
Window root_win = RootWindow( display, screen );
if ( !glXQueryExtension( display, 0, 0 ) )
printf( "X Server doesn't support GLX extension\n" );
// Pick a visual
XVisualInfo *visinfo = chooseVisual( display );
if ( visinfo == 0 )
printf( "glXChooseVisual failed\n" );
// Describe the visual
printf( "Window Visual 0x%.2x\n", unsigned( visinfo->visualid ) );
// Create the X window
XSetWindowAttributes winAttr ;
winAttr.event_mask = StructureNotifyMask | KeyPressMask ;
winAttr.background_pixmap = None ;
winAttr.background_pixel = 0 ;
winAttr.border_pixel = 0 ;
winAttr.colormap = XCreateColormap( display, root_win,
visinfo->visual, AllocNone );
unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
Window win = Win.win = XCreateWindow ( display, root_win,
WIN_XPOS, WIN_YPOS,
WIN_XRES, WIN_YRES, 0,
visinfo->depth, InputOutput,
visinfo->visual, mask, &winAttr ) ;
XStoreName( Win.display, win, "My GLX Window");
// Create an OpenGL context and attach it to our X window
GLXContext context = glXCreateContext( display, visinfo, NULL, 1 ) ;
if ( ! glXMakeCurrent( display, win, context ) )
printf( "glXMakeCurrent failed.\n" );
if ( ! glXIsDirect ( display, glXGetCurrentContext() ) )
printf( "Indirect GLX rendering context obtained\n" );
// Display the window
XMapWindow( display, win );
if ( ! glXMakeCurrent( display, win, context ) )
printf( "glXMakeCurrent failed.\n" );
check( "createWindow()" );
printf( "Window Size = %d x %d\n", WIN_XRES, WIN_YRES );
printf( "Window Samples = %d\n", NUM_SAMPLES );
}
//----------------------------------------------------------------------------
void processXEvents( Atom wm_protocols, Atom wm_delete_window )
{
bool setting_change = false;
while ( XEventsQueued( Win.display, QueuedAfterFlush ) )
{
XEvent event;
XNextEvent( Win.display, &event );
if( event.xany.window != Win.win )
continue;
switch ( event.type )
{
case MapNotify:
{
Win.displayed = true;
break;
}
case ConfigureNotify:
{
XConfigureEvent &cevent = event.xconfigure;
reshapeCB( cevent.width, cevent.height );
break;
}
case KeyPress:
{
char chr;
KeySym symbol;
XComposeStatus status;
XLookupString( &event.xkey, &chr, 1, &symbol, &status );
keyboardCB( symbol, chr, event.xkey.x, event.xkey.y,
setting_change );
break;
}
case ClientMessage:
{
if ( event.xclient.message_type == wm_protocols &&
Atom( event.xclient.data.l[0] ) == wm_delete_window )
{
//printf( "Received WM_DELETE_WINDOW\n" );
exit(0);
}
break;
}
}
}
}
//----------------------------------------------------------------------------
void mainLoop()
{
// Register to receive window close events (the "X" window manager button)
Atom wm_protocols = XInternAtom( Win.display, "WM_PROTOCOLS" , False);
Atom wm_delete_window = XInternAtom( Win.display, "WM_DELETE_WINDOW", False);
XSetWMProtocols( Win.display, Win.win, &wm_delete_window, True );
while (1)
{
// Redraw window (after it's mapped)
if ( Win.displayed )
displayCB();
// Update frame rate
static timeval last_xcheck = {0,0};
struct timeval now;
gettimeofday( &now, 0 );
// Check X events every 1/10 second
if ( elapsedMsec( last_xcheck, now ) > 100 )
{
processXEvents( wm_protocols, wm_delete_window );
last_xcheck = now;
}
}
}
//----------------------------------------------------------------------------
int main( int argc, char *argv[] )
{
// Init globals
Win.width = WIN_XRES, Win.height = WIN_YRES;
// Create context and window
createWindow();
// Init OpenGL
glViewport ( 0, 0, Win.width, Win.height );
glColorMask ( 1,1,1,1 );
glClearColor( 0,0,1,1 );
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Go
printf( "Valid keys: Left, Right, k, ESC\n" );
printf( "Press ESC to quit\n" );
mainLoop();
return 0;
}
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.