/*
 * GLX overlay test/demo.
 *
 * Brian Paul
 * 18 July 2005
 */

#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/keysym.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

static int WinWidth = 300, WinHeight = 300;
static Window NormalWindow = 0;
static Window OverlayWindow = 0;
static GLXContext NormalContext = 0;
static GLXContext OverlayContext = 0;
static GLboolean RGBOverlay = GL_FALSE;
static GLfloat Angle = 0.0;


static void
RedrawNormal(Display *dpy)
{
   glXMakeCurrent(dpy, NormalWindow, NormalContext);
   glViewport(0, 0, WinWidth, WinHeight);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
   glClearColor(0.5, 0.5, 0.5, 1.0);
   glClear(GL_COLOR_BUFFER_BIT);
   glColor3f(1.0, 1.0, 0.0);
   glPushMatrix();
   glRotatef(Angle, 0, 0, 1);
   glRectf(-0.8, -0.8, 0.8, 0.8);
   glPopMatrix();
   glXSwapBuffers(dpy, NormalWindow);
}


static void
RedrawOverlay(Display *dpy)
{
   glXMakeCurrent(dpy, OverlayWindow, OverlayContext);
   glViewport(0, 0, WinWidth, WinHeight);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
   glClear(GL_COLOR_BUFFER_BIT);
   if (RGBOverlay) {
      glColor3f(0.0, 1.0, 1.0);
   }
   else {
      glIndexi(2);
   }
   glBegin(GL_LINES);
   glVertex2f(-1, -1);
   glVertex2f(1, 1);
   glVertex2f(1, -1);
   glVertex2f(-1, 1);
   glEnd();
   glXSwapBuffers(dpy, OverlayWindow);
}


static Window
MakeWindow(Display *dpy, XVisualInfo *visinfo, Window parent,
             unsigned int width, unsigned int height)
{
   int scrnum;
   XSetWindowAttributes attr;
   unsigned long mask;
   Window root;
   Window win;

   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, parent, 0, 0, width, height,
		        0, visinfo->depth, InputOutput,
		        visinfo->visual, mask, &attr);
   return win;
}


static void
MakeNormalWindow(Display *dpy)
{
   int attrib[] = { GLX_RGBA,
		    GLX_RED_SIZE, 1,
		    GLX_GREEN_SIZE, 1,
		    GLX_BLUE_SIZE, 1,
		    GLX_DOUBLEBUFFER,
		    None };
   int scrnum;
   Window root;
   XVisualInfo *visinfo;

   scrnum = DefaultScreen(dpy);
   root = RootWindow(dpy, scrnum);

   visinfo = glXChooseVisual(dpy, scrnum, attrib);
   if (!visinfo) {
      printf("Error: couldn't get an RGB, Double-buffered visual\n");
      exit(1);
   }

   NormalWindow = MakeWindow(dpy, visinfo, root, WinWidth, WinHeight);
   assert(NormalWindow);

   NormalContext = glXCreateContext(dpy, visinfo, NULL, True);
   assert(NormalContext);
}


static void
MakeOverlayWindow(Display *dpy)
{
   int rgbAttribs[] = {
      GLX_RGBA,
      GLX_RED_SIZE, 1,
      GLX_GREEN_SIZE, 1,
      GLX_BLUE_SIZE, 1,
      GLX_DOUBLEBUFFER,
      GLX_LEVEL, 1,
      None
   };
   int indexAttribs[] = {
      /*GLX_RGBA, leave this out */
      GLX_RED_SIZE, 1,
      GLX_GREEN_SIZE, 1,
      GLX_BLUE_SIZE, 1,
      GLX_DOUBLEBUFFER,
      GLX_LEVEL, 1,
      None
   };
   int scrnum;
   Window root;
   XVisualInfo *visinfo;

   scrnum = DefaultScreen(dpy);
   root = RootWindow(dpy, scrnum);

   visinfo = glXChooseVisual(dpy, scrnum, rgbAttribs);
   if (visinfo) {
      printf("Found RGB overlay visual 0x%x\n", (int) visinfo->visualid);
      RGBOverlay = GL_TRUE;
   }
   else {
      visinfo = glXChooseVisual(dpy, scrnum, indexAttribs);
      if (visinfo) {
         printf("Found Color Index overlay visual 0x%x\n",
                (int) visinfo->visualid);
         /* XXX setup the colormap entries! */
      }
      else {
         printf("Error: couldn't get an overlay visual!\n");
         exit(1);
      }
   }

   OverlayWindow = MakeWindow(dpy, visinfo, NormalWindow, WinWidth, WinHeight);
   assert(OverlayWindow);

   OverlayContext = glXCreateContext(dpy, visinfo, NULL, True);
   assert(OverlayContext);
}


static void
EventLoop(Display *dpy)
{
   XEvent event;

   while (1) {
      XNextEvent(dpy, &event);

      switch (event.type) {
	 case Expose:
	    RedrawNormal(dpy);
	    RedrawOverlay(dpy);
	    break;
	 case ConfigureNotify:
            WinWidth = event.xconfigure.width;
            WinHeight = event.xconfigure.height;
            if (event.xconfigure.window == NormalWindow)
               XResizeWindow(dpy, OverlayWindow, WinWidth, WinHeight);
	    break;
         case KeyPress:
            {
               char buffer[10];
               int r, code;
               code = XLookupKeysym(&event.xkey, 0);
	       r = XLookupString(&event.xkey, buffer, sizeof(buffer),
				 NULL, NULL);
	       if (buffer[0] == 27) {
                  /* escape */
                  return;
               }
               else if (buffer[0] == ' ') {
                  Angle += 5.0;
                  RedrawNormal(dpy);
               }
            }
            break;
         default:
            ; /* nothing */
      }
   }
}


int
main(int argc, char *argv[])
{
   Display *dpy = XOpenDisplay(NULL);

   assert(dpy);

   MakeNormalWindow(dpy);
   MakeOverlayWindow(dpy);

   XMapWindow(dpy, NormalWindow);
   XMapWindow(dpy, OverlayWindow);

   EventLoop(dpy);

   glXDestroyContext(dpy, OverlayContext);
   glXDestroyContext(dpy, NormalContext);
   XDestroyWindow(dpy, OverlayWindow);
   XDestroyWindow(dpy, NormalWindow);

   return 0;
}
