
#include <stdio.h>
#include <stdlib.h>
#include <GL/glx.h>
#include <X11/Xutil.h>

extern void runTests( int, int );

int  testWidth = 512;
int  testHeight = 512;
const int  borderWidth = 20;
const int  borderHeight = 20;

int numTrials = 10;


int  doubleBuffer = GL_FALSE;
char*  progname;

//----------------------------------------------------------------------------

void
usage( bool helpMode = false )
{
  printf( "%s: [-h] [-n #]\n"
	  " -h  : print this message\n"
	  " -n #: render '#' times for each pixel format\n"
	  " -v  : echo command line\n",
	  progname );

  exit( helpMode ? EXIT_SUCCESS : EXIT_FAILURE );
}
//----------------------------------------------------------------------------

Bool
waitForWindow( Display*, XEvent* event, XPointer arg )
{
  return (event->type == MapNotify && event->xmap.window == (Window) arg);
}

//----------------------------------------------------------------------------

void
createWindow( Display* dpy, XVisualInfo* vi )
{
  //--------------------------------------------------------------------------
  //
  //  Create and Setup X window for OpenGL rendering
  //
  XSetWindowAttributes  swa;
  swa.colormap = XCreateColormap( dpy, RootWindow(dpy, 0),
				  vi->visual, AllocNone );
  swa.border_pixel = BlackPixel( dpy, 0 );
  swa.event_mask = StructureNotifyMask;
  
  unsigned long  swaMask = CWColormap|CWBorderPixel|CWEventMask;

  int  winWidth = testWidth + 2*borderWidth;
  int  winHeight = testHeight + 2*borderHeight;

  Window win = XCreateWindow( dpy, RootWindow(dpy, 0), 100, 100, winWidth,
			      winHeight, 0, vi->depth, InputOutput, vi->visual,
			      swaMask, &swa );

  XSizeHints  hints;
  hints.flags = USPosition | USSize;
  hints.x = 100;
  hints.y = 100;
  hints.width = winWidth;
  hints.height = winHeight;
  
  XSetWMNormalHints( dpy, win, &hints );

  XMapWindow( dpy, win );

  XEvent  event;
  XIfEvent( dpy, &event, waitForWindow, (XPointer) win );

  GLXContext  ctx = glXCreateContext( dpy, vi, NULL, GL_TRUE );

  glXMakeCurrent( dpy, win, ctx );

  int r, g, b, a;
  glXGetConfig( dpy, vi, GLX_RED_SIZE, &r );
  glXGetConfig( dpy, vi, GLX_GREEN_SIZE, &g );
  glXGetConfig( dpy, vi, GLX_BLUE_SIZE, &b );
  glXGetConfig( dpy, vi, GLX_ALPHA_SIZE, &a );

  printf( "Component Depths : ( %d, %d, %d, %d ) %s Buffered [ 0x%X ]\n",
	  r, g, b, a, (char *) doubleBuffer ? "Double" : "Single",
	  vi->visualid );
  
  //--------------------------------------------------------------------------
  //
  //  Initialize OpenGL State
  //

  glViewport( 0, 0, winWidth, winHeight );
  glMatrixMode( GL_PROJECTION );
  glOrtho( -borderWidth, testWidth + borderWidth,
	   -borderHeight, testHeight + borderHeight,
	   -1.0, 1.0 );
  glMatrixMode( GL_MODELVIEW );

  if ( doubleBuffer )
    glDrawBuffer( GL_FRONT );

  //
  //  Run Tests
  //
  
  runTests( testWidth, testHeight );

  printf( "\n" );

  glXMakeCurrent( dpy, None, NULL );
  XUnmapWindow( dpy, win );

  XFreeColormap( dpy, swa.colormap );
  XDestroyWindow( dpy, win );
}

//----------------------------------------------------------------------------

int
main( int argc, char** argv )
{
  int  i, n;

  for ( i = 1; i < argc; ++i ) {
    char*  tmp = argv[i];

    if ( *tmp != '-' )
      usage();

    ++tmp;

    switch ( *tmp ) {
      case 'n':
	if ( argv[++i] )
	  numTrials = atoi( argv[i] );
	else
	  usage();
      break;

      case 'g':
	if ( argv[++i] ) 
	  testWidth = atoi( argv[i] );
	else
	  usage();

	if ( argv[++i] )
	  testHeight = atoi( argv[i] );
	else
	  usage();
	break;

      case 'v': {
	int arg;
	for ( arg = 0; arg < argc; ++arg )
	  printf( "%s ", argv[arg] );
	printf( "\n" );
      } break;

      default:
	usage( *tmp == 'h' );
    }
  }
  
  Display*  dpy = XOpenDisplay( NULL );
  if ( !dpy )
    return EXIT_FAILURE;

  XVisualInfo  vTmp;
  vTmp.screen = DefaultScreen( dpy );

  long vMask = VisualScreenMask;

  XVisualInfo*  vInfo = XGetVisualInfo( dpy, vMask, &vTmp, &n );
  if ( n == 0 )
    return EXIT_FAILURE;

  for ( i = 0; i < n; ++i ) {
    XVisualInfo *vi = &vInfo[i];

    if ( vi->c_class != TrueColor )
      continue;

    int  value;
    glXGetConfig( dpy, vi, GLX_USE_GL, &value );
    if ( !value )
      continue;

    glXGetConfig( dpy, vi, GLX_LEVEL, &value );  // Skip overlay planes
    if ( value != 0 )
      continue;

    glXGetConfig( dpy, vi, GLX_STENCIL_SIZE, &value );
    if ( value > 0 )
      continue;

    glXGetConfig( dpy, vi, GLX_DOUBLEBUFFER, &doubleBuffer );

    createWindow( dpy, vi );
  }

  XCloseDisplay( dpy );

  return EXIT_SUCCESS;
}
