/*
 * "$Id: glxpixmap.c,v 1.2 2003/06/10 03:49:02 mike Exp $"
 *
 * GLX pixmap example using only Xlib and GLX.
 *
 * Copyright 2003 by Michael Sweet, All Rights Reserved.
 */

/*
 * Include necessary headers...
 */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <GL/glx.h>
#include <GL/gl.h>


/*
 * Globals...
 */

float		CubeRotation[3],	/* Rotation of cube */
		CubeRate[3];		/* Rotation rate of cube */
int		CubeWidth,		/* Width of window */
		CubeHeight;		/* Height of window */


/*
 * Functions...
 */

void		DisplayFunc(void);


/*
 * 'main()' - Main entry for example program.
 */

int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line args */
{
  GLXContext		context;	/* OpenGL context */
  Display		*display;	/* X display connection */
  Pixmap		pixmap;		/* X pixmap */
  GLXPixmap		glxpixmap;	/* GLX pixmap */
  XVisualInfo		*vinfo;		/* X visual information */
  FILE			*fp;		/* PPM file pointer */
  int			y;		/* Current row */
  unsigned char		pixels[3072];	/* One line of RGB pixels */
  static int 		attributes[] =	/* OpenGL attributes */
			{
			  GLX_RGBA,
			  GLX_RED_SIZE, 8,
			  GLX_GREEN_SIZE, 8,
			  GLX_BLUE_SIZE, 8,
			  GLX_DEPTH_SIZE, 16,
			  0,		/* Save space for GLX_DOUBLEBUFFER */
			  0
			};


 /*
  * Open a connection to the X server...
  */

  display = XOpenDisplay(getenv("DISPLAY"));

 /*
  * Find the proper visual for a GLX pixmap...
  */

  vinfo = glXChooseVisual(display, DefaultScreen(display), attributes);
  if (!vinfo)
  {
   /*
    * If no single-buffered visual is available, try a double-buffered one...
    */

    attributes[9] = GLX_DOUBLEBUFFER;
    vinfo         = glXChooseVisual(display, DefaultScreen(display),
                                    attributes);
  }

  if (!vinfo)
  {
    puts("No OpenGL visual available!");
    return (1);
  }

 /*
  * Create the pixmap...
  */

  pixmap    = XCreatePixmap(display, DefaultRootWindow(display),
                            1024, 1024, vinfo->depth);
  glxpixmap = glXCreateGLXPixmap(display, vinfo, pixmap);

 /*
  * Create the OpenGL context...
  */

  context = glXCreateContext(display, vinfo, 0, False);
  glXMakeCurrent(display, glxpixmap, context);

 /*
  * Setup remaining globals...
  */

  CubeWidth       = 1024;
  CubeHeight      = 1024;
  CubeRotation[0] = 45.0f;
  CubeRotation[1] = 45.0f;
  CubeRotation[2] = 45.0f;
  CubeRate[0]     = 1.0f;
  CubeRate[1]     = 1.0f;
  CubeRate[2]     = 1.0f;

 /*
  * Draw a cube...
  */

  DisplayFunc();

 /*
  * Read back the RGB pixels and write the result as a PPM file.
  */

  if ((fp = fopen("glxpixmap.ppm", "wb")) == NULL)
    perror("Unable to create glxpixmap.ppm");
  else
  {
   /*
    * Write a PPM image from top to bottom...
    */

    fputs("P6\n1024 1024 255\n", fp);

    for (y = 1023; y >= 0; y --)
    {
      glReadPixels(0, y, 1024, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels);
      fwrite(pixels, 1024, 3, fp);
    }

    fclose(fp);
  }

 /*
  * Destroy all resources we used and close the display...
  */

  glXDestroyContext(display, context);
  glXDestroyGLXPixmap(display, glxpixmap);
  XFreePixmap(display, pixmap);
  XCloseDisplay(display);

  return (0);
}


/*
 * 'DisplayFunc()' - Draw a cube.
 */

void
DisplayFunc(void)
{
  int			i, j;		/* Looping vars */
  static const GLfloat	corners[8][3] =	/* Corner vertices */
			{
			  {  1.0f,  1.0f,  1.0f },	/* Front top right */
			  {  1.0f, -1.0f,  1.0f },	/* Front bottom right */
			  { -1.0f, -1.0f,  1.0f },	/* Front bottom left */
			  { -1.0f,  1.0f,  1.0f },	/* Front top left */
			  {  1.0f,  1.0f, -1.0f },	/* Back top right */
			  {  1.0f, -1.0f, -1.0f },	/* Back bottom right */
			  { -1.0f, -1.0f, -1.0f },	/* Back bottom left */
			  { -1.0f,  1.0f, -1.0f }	/* Back top left */
			};
  static const int	sides[6][4] =	/* Sides */
			{
			  { 0, 1, 2, 3 },		/* Front */
			  { 4, 5, 6, 7 },		/* Back */
			  { 0, 1, 5, 4 },		/* Right */
			  { 2, 3, 7, 6 },		/* Left */
			  { 0, 3, 7, 4 },		/* Top */
			  { 1, 2, 6, 5 }		/* Bottom */
			};
  static const GLfloat	colors[6][3] =	/* Colors */
			{
			  { 1.0f, 0.0f, 0.0f },		/* Red */
			  { 0.0f, 1.0f, 0.0f },		/* Green */
			  { 1.0f, 1.0f, 0.0f },		/* Yellow */
			  { 0.0f, 0.0f, 1.0f },		/* Blue */
			  { 1.0f, 0.0f, 1.0f },		/* Magenta */
			  { 0.0f, 1.0f, 1.0f }		/* Cyan */
			};


 /*
  * Clear the window...
  */

  glViewport(0, 0, CubeWidth, CubeHeight);
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Setup the matrices...
  */

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-2.0f, 2.0f,
          -2.0f * CubeHeight / CubeWidth, 2.0f * CubeHeight / CubeWidth,
          -2.0f, 2.0f);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glRotatef(CubeRotation[0], 1.0f, 0.0f, 0.0f);
  glRotatef(CubeRotation[1], 0.0f, 1.0f, 0.0f);
  glRotatef(CubeRotation[2], 0.0f, 0.0f, 1.0f);

 /*
  * Draw the cube...
  */

  glEnable(GL_DEPTH_TEST);

  glBegin(GL_QUADS);

  for (i = 0; i < 6; i ++)
  {
    glColor3fv(colors[i]);
    for (j = 0; j < 4; j ++)
      glVertex3fv(corners[sides[i][j]]);
  }

  glEnd();
}


/*
 * End of "$Id: glxpixmap.c,v 1.2 2003/06/10 03:49:02 mike Exp $".
 */
