#pragma ident	"@(#)ogl_overlay_ex3.c	1.3	05/21/98 OGL SMI"

/*
** ogl_overlay_ex3.c
**
** This program demonstrates the use of the SERVER_OVERLAY_VISUALS (SOV) 
** interface to create an overlay window and render transparency to it.  
** It demonstrates the following aspects of using transparent overlays 
** with this interface:
**
** 1. Finding a transparent overlay visual and its transparent pixel
**
**    The visual which has TransparentType = TransparentPixel (0x1) in the 
**    property SERVER_OVERLAY_VISUAL on the root window is an overlay whose 
**    pixels are stored in separate pixel memory from normal (underlay) visuals 
**    See the function findSovVisual() for an example of how to select
**    this visual.
**
**    Once a transparent overlay visual is found, the transparent pixel
**    value is a field in the SERVER_OVERLAY_VISUAL property entry for 
**    that visual.
**
** 2. Creating a correlated overlay/underlay window pair.
**
**    In this example, the overlay window is created as a child of the 
**    underlay window.   This makes it easier to maintain the same shape
**    and position for the overlay and underlay, as required in order to
**    use SOV.   For example, when the underlay moves, the overlay moves 
**    along with it.  But the application still needs to manually resize 
**    the overlay whenever the underlay window size changes.  See olReshape().
**
** 3. Creating an overlay colormap
**
**    In most configurations, the overlay visual is not the default visual.
**    Thus, a separate overlay colormap may need to be created.   See 
**    olCreateAndInit().  If this is needed, the window manager needs to be 
**    informed about this colormap by calling XSetWMColormapWindows so that 
**    the window manager can install the overlay colormap whenever the pointer
**    enters the window pair.   
**
** 4. Reducing overlay colormap flashing
**
**    On single hardware colormap devices (such as Creator) overlay colormaps 
**    may flash with underlay colormaps, most particularly the default colormap.   
**    To avoid this, it is best to allocate the overlay colors at the high end 
**    of the colormap.  This works even on multiple hardware colormap devices. 
**    See olCreateAndInit().
**
** 5. Ways to use the transparent pixel
**
**    As demonstrated by this program, a transparent pixel can be used in
**    several different ways.   To draw opaque figures on top of the
**    underlay, the transparent pixel can be used as a ClearIndex value,
**    to clear the entire overlay window to transparent.  Or, to "punch
**    through" to display the underlay, the overlay window can be cleared
**    to an opaque color and the transparent pixel can be used as a 
**    foreground color (glIndex*).   The transparent pixel can even be
**    used in the data given to glDrawPixels.
*/

#include <math.h> 
#include <string.h> 
#include <stdio.h> 
#include <malloc.h>
#include <sys/time.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <Xm/PushBP.h>
#include <Xm/RowColumn.h>
#include <GL/gl.h>
#include <GL/glx.h>



#define SOV_PROP_NAME "SERVER_OVERLAY_VISUALS"
#define TransTypePixel 0x1

/*
 * This should be CARD64 but CARD64 is not available 
 * with Solaris 2.5.1 so 'long' is used instead.
 */
#define SOV_CARD long

typedef struct {
    SOV_CARD visualID;
    SOV_CARD trans_type;
    SOV_CARD transPixel;
    SOV_CARD layer;
} SovPropFormat;

#define PI 3.141592654
#define NUM_FACETS      20
#define NUM_VERTICES    12
#define NUM_V_PER_F      3


void get_accelerated_x_visual ();
void ul_traverse ();
void ol_traverse ();
void no_highlight_proc ();
void button_callback_draw_text ();
void button_callback_draw_points ();
void button_callback_draw_lines ();
void button_callback_draw_tris ();
void button_callback_draw_pixels ();
void button_callback_change_color ();
void button_callback_rot_ulay ();
void button_callback_undraw_olay ();
void button_callback_reverse_transp ();
void button_callback_quit ();

int dbuf;
int depth;
int numDummyColors = 0;
unsigned long dummyPixels[256];

typedef struct {
   int x;
   int y;
   int last_x;
   int last_y;
} mouse_data;

typedef struct {
   float x;
   float y;
} save_diff;

#define NOCOLOR         0
#define TRANSPARENT     1
#define WHITE           2
#define BLACK           3
#define RED             4
#define GREEN           5
#define BLUE            6

typedef struct {
    int frgd;
    int bkgd;
    int frgdPixel;
    int bkgdPixel;
} olColorRec;

olColorRec olColors[] = {
    WHITE,        TRANSPARENT, 0, 0,
    BLACK,        TRANSPARENT, 0, 0,
    RED,          TRANSPARENT, 0, 0,
    GREEN,        TRANSPARENT, 0, 0,
    BLUE,         TRANSPARENT, 0, 0,
    NOCOLOR,      NOCOLOR,     0, 0
};

#define DRAWPIX_BKGD_COLOR_NAME "purple"
XColor drawPixBkgd;

int olCurColor = 0;
int clearOverlayOnTraverse = 1;	/* set to 0 in undraw proc */
int transparentForeground;

int cpv = 0;

int winWidth  = 400;
int winHeight = 400;

Pixel pixTp;

int textOn = 0;
int pointsOn = 0;
int linesOn = 0; 
int trisOn = 0;
int drawPixOn = 0;
int     rotate;
GLfloat x_deg;
GLfloat y_deg;

GLfloat angleY = 0.0;
GLfloat angleX = 0.0;
GLfloat angleYdelta = 0.0;
GLfloat angleXdelta = 0.0;
int     basey;
int     basex;

mouse_data data;
save_diff data_save[16];

int max_colors = 256;
int status;
int size;
int ol_color_index = 0;
int rubberband = FALSE;
int transparent = FALSE;

double rotation_angle = 0.;
double degrees10 = PI/18.0;

unsigned int color_mapping[256];
unsigned int draw_buffer;
unsigned int display_buffer;
unsigned int draw_buffer2;
unsigned int display_buffer2;

Colormap ul_colormap;
Colormap ol_colormap;
Colormap default_colormap;
XColor xcolor[256];
Display *dpy = NULL;
Window ul_window;
Window  ol_window;
Window window;
Window window2;
Window root;
Atom protocol_atom;
Atom kill_atom;

XVisualInfo   *ulvisinfo;
XVisualInfo   *olvisinfo;
SovPropFormat *sovinfo;

GLXContext olctx;
GLXContext ulctx;

typedef struct point {
    GLfloat x;
    GLfloat y;
} Point;

#define SECTIONS_NUM_HORIZ   2
#define SECTIONS_NUM_VERT    3

#define SECTION_LINE    0
#define SECTION_TRIS    1
#define SECTION_TEXT    2
#define SECTION_POINTS  3
#define SECTION_DRAWPIX 4

Point section[6];
GLfloat sectionDeltaH, sectionDeltaV;
GLfloat sectionInitH, sectionInitV;

int     screen;

#define FONT_NAME "-adobe-courier-bold-r-normal--14-140-75-75-m-90-iso8859-1"
#define NUM_CHAR  128

Font    font;
int     fontDlBase;

void
initFontDlist ()
{
    font = XLoadFont(dpy, FONT_NAME);
    fontDlBase = glGenLists(NUM_CHAR);
    glXUseXFont(font, 0, NUM_CHAR, fontDlBase);
}


void
ulSelectVisual ()
{
    XVisualInfo *vinfos, *thisvis;
    XVisualInfo template;
    int         nvis, i;
    int         val;

    template.screen = screen;
    vinfos = XGetVisualInfo(dpy, VisualScreenMask, &template, &nvis);

    ulvisinfo = NULL;
    for (i = 0; i < nvis; i++) {
	thisvis = &vinfos[i];

	/* Looking for 24-bit TrueColor */
	if (thisvis->depth != 24 && thisvis->class != TrueColor) continue;

	/* Visual must be supported by GLX */
	if ( glXGetConfig(dpy, thisvis, GLX_USE_GL, &val) ) continue;
	if ( !val ) continue;

	/* Visual must be in main planes which is level 0 */
	glXGetConfig(dpy, thisvis, GLX_LEVEL, &val);
	if ( val != 0 ) continue;
	
	ulvisinfo = thisvis;
	break;
    }

    if (!ulvisinfo) {
	fprintf(stderr, "Cannot find suitable underlay visual\n");
	exit(1);
    }

    depth = 24;

    /* Is this visual double buffered or Single buffered? */
    glXGetConfig( dpy, thisvis, GLX_DOUBLEBUFFER, &dbuf);
}

void
ulCmapCreate ()
{
    ul_colormap = XCreateColormap (dpy,
				   RootWindow (dpy, screen),
				   ulvisinfo->visual,
				   AllocNone);
}


void
ulCtxCreateAndInit ()
{
    GLfloat specular[4] = {0.8, 0.2, 0.2, 1.0};
    GLfloat position[4] = {2.0, 2.0, 100.0, 1.0};

    ulctx = glXCreateContext(dpy, ulvisinfo, NULL, True);
    glXMakeCurrent(dpy, ul_window, ulctx);

    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);

    glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT1, GL_POSITION, position);
    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 0);
    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 15);
}


void
olCtxCreateAndInit ()
{
    olctx = glXCreateContext(dpy, olvisinfo, NULL, True);
    glXMakeCurrent(dpy, ol_window, olctx);

    glShadeModel(GL_FLAT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
}


void
ulReshape (int w, int h)
{
    glXMakeCurrent(dpy, ul_window, ulctx);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.0, (GLfloat)w / (GLfloat)h, 0.01, 1000.0);
    glMatrixMode(GL_MODELVIEW);

    glViewport(0, 0, w, h);
}

void
olReshape (int w, int h)
{
    XWindowChanges    chg;
    int               i;

    chg.width  = w;
    chg.height = h;
    XConfigureWindow(dpy, ol_window, CWWidth | CWHeight, &chg);
    XSync (dpy, FALSE);
    
    glXMakeCurrent(dpy, ol_window, olctx);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glViewport(0, 0, w, h);
}

void
reshape (int w, int h)
{
    ulReshape(w, h);
    olReshape(w, h);
}

void
findSovVisual (XVisualInfo **visinfo, SovPropFormat **sovinfo)
{
    XVisualInfo     *vinfo, template;
    int             attrs[3];
    int             i, n, nvis;
    int	            actualFormat;
    unsigned long   sizeData;
    unsigned long   bytesLeft;
    Atom 	    actualType;
    Atom	    sov_atom;
    SovPropFormat   *propArray;

    sov_atom = XInternAtom(dpy, SOV_PROP_NAME, True);
    if (sov_atom == None) {
	fprintf(stderr, "Cannot create an atom for the property SERVER_OVERLAY_VISUALS\n");
	exit(1);
    }

    if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), 
			   sov_atom,0, 10000, False, sov_atom,
			   &actualType, &actualFormat, &sizeData,
			   &bytesLeft, (char**) &propArray) == Success) { 
	if (actualType == sov_atom) {
	    n = sizeData / (sizeof(SovPropFormat) / sizeof(SOV_CARD));
	    for (i = 0; i < n; i++) {
		SovPropFormat *p = propArray + i;
		if (p->trans_type == TransTypePixel) {
		    *sovinfo = p;
		    template.screen = screen;
		    template.visualid = p->visualID;
		    *visinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, 
					      &template, &nvis);
		    if (*visinfo == NULL || nvis == 0) {
			fprintf(stderr, "Cannot get visual info for SOV visual\n");
			exit(1);
		    }
		    return;
		}
	    }
	}
    }
    
    fprintf(stderr, "Cannot find a SOV visual on this screen\n");
    exit(1);
}

#define NUM_COLOR_CELLS 		5
#define NUM_COLORS_RESERVED_FOR_WM	16

void
olCreateAndInit ()
{
    unsigned long plane_masks[2];
    unsigned long ol_color_mapping[NUM_COLOR_CELLS];
    XColor       xcolor[256];
    XColor       dummyColor;
    int          i, pixWhite, pixBlack, 
                 pixRed, pixGreen, pixBlue;
    XSetWindowAttributes attr;

    findSovVisual(&olvisinfo, &sovinfo);

    if (olvisinfo->visual != DefaultVisual(dpy, screen)) {
        ol_colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
				  olvisinfo->visual, AllocNone);

	/* 
	** Put the overlay colors at the high end of the overlay
	** colormap in order to avoid the desktop colors.
	*/
        numDummyColors = olvisinfo->colormap_size - NUM_COLOR_CELLS -
                         NUM_COLORS_RESERVED_FOR_WM - 1;
        if (!XAllocColorCells (dpy, ol_colormap, (Bool) TRUE, plane_masks, 0,
                      dummyPixels, numDummyColors)) {
	    fprintf(stderr, "allocation of dummy colors failed\n");
	}
    } else {
	ol_colormap = DefaultColormap(dpy, screen);
    }

    if (!XAllocColorCells (dpy, ol_colormap, (Bool) TRUE, plane_masks, 0,
                      ol_color_mapping, NUM_COLOR_CELLS)) {
	fprintf(stderr, "allocation of overlay colors failed\n");
	exit(1);
    }

    xcolor[0].flags = DoRed | DoGreen | DoBlue;
    xcolor[0].pixel = ol_color_mapping[0];
    xcolor[0].red   = 65535;
    xcolor[0].green = 65535;
    xcolor[0].blue  = 65535;
    pixWhite = ol_color_mapping[0];

    xcolor[1].flags = DoRed | DoGreen | DoBlue;
    xcolor[1].pixel = ol_color_mapping[1];
    xcolor[1].red   =     0;
    xcolor[1].green =     0;
    xcolor[1].blue  =     0;
    pixBlack = ol_color_mapping[1];

    xcolor[2].flags = DoRed | DoGreen | DoBlue;
    xcolor[2].pixel = ol_color_mapping[2];
    xcolor[2].red   = 65535;
    xcolor[2].green =     0;
    xcolor[2].blue  =     0;
    pixRed = ol_color_mapping[2];

    xcolor[3].flags = DoRed | DoGreen | DoBlue;
    xcolor[3].pixel = ol_color_mapping[3];
    xcolor[3].red   =     0;
    xcolor[3].green = 65535;
    xcolor[3].blue  =     0;
    pixGreen = ol_color_mapping[3];

    xcolor[4].flags = DoRed | DoGreen | DoBlue;
    xcolor[4].pixel = ol_color_mapping[4];
    xcolor[4].red   =     0;
    xcolor[4].green =     0;
    xcolor[4].blue  = 65535;
    pixBlue = ol_color_mapping[4];

    XStoreColors (dpy, ol_colormap, xcolor, 5);
    XSync (dpy, FALSE);

    XAllocNamedColor(dpy, ol_colormap, DRAWPIX_BKGD_COLOR_NAME,
		     &drawPixBkgd, &dummyColor);

    /* Now free any placeholder cells allocated */
    if (olvisinfo->visual != DefaultVisual(dpy, screen)) {
	XFreeColors(dpy, ol_colormap, dummyPixels, numDummyColors, 0);
    }

    attr.border_pixel = xcolor[0].pixel;
    attr.colormap = ol_colormap;
    attr.event_mask = ExposureMask;
    attr.background_pixmap = None;
    ol_window = XCreateWindow(dpy, ul_window,
			      0, 0, winWidth, winHeight,
			      0, 8,
			      InputOutput,
			      olvisinfo->visual,
			      CWEventMask | CWBorderPixel | CWColormap |
				  CWBackPixmap,
			      &attr);

    pixTp = sovinfo->transPixel;
    
    i = 0;
    while (1) {
	if (olColors[i].frgd == NOCOLOR) {
	    break;
	}
	if        (olColors[i].frgd == WHITE) {
	    olColors[i].frgdPixel = pixWhite;
	} else if (olColors[i].frgd == BLACK) {
	    olColors[i].frgdPixel = pixBlack;
	} else if (olColors[i].frgd == RED) {
	    olColors[i].frgdPixel = pixRed;
	} else if (olColors[i].frgd == GREEN) {
	    olColors[i].frgdPixel = pixGreen;
	} else if (olColors[i].frgd == BLUE) {
	    olColors[i].frgdPixel = pixBlue;
	} else if (olColors[i].frgd == TRANSPARENT) {
	    olColors[i].frgdPixel = pixTp;
	    transparentForeground = i;
	}
	if        (olColors[i].bkgd == WHITE) {
	    olColors[i].bkgdPixel = pixWhite;
	} else if (olColors[i].bkgd == BLACK) {
	    olColors[i].bkgdPixel = pixBlack;
	} else if (olColors[i].bkgd == RED) {
	    olColors[i].bkgdPixel = pixRed;
	} else if (olColors[i].bkgd == GREEN) {
	    olColors[i].bkgdPixel = pixGreen;
	} else if (olColors[i].bkgd == BLUE) {
	    olColors[i].bkgdPixel = pixBlue;
	} else if (olColors[i].bkgd == TRANSPARENT) {
	    olColors[i].bkgdPixel = pixTp;
	}

	i++;
    }

}


void
calcSections ()
{
    int i, k, s;

    sectionInitV = 0.0;
    sectionInitH = 0.0;

    sectionDeltaV = (GLfloat)winHeight / (GLfloat)SECTIONS_NUM_VERT;
    sectionDeltaH = (GLfloat)winWidth  / (GLfloat)SECTIONS_NUM_HORIZ;

    s = 0;
    for (i = 0; i < SECTIONS_NUM_VERT-1; i++) {
	for (k = 0; k < SECTIONS_NUM_HORIZ; k++) {
	    section[s].y = i * sectionDeltaV;
	    section[s].x = k * sectionDeltaH;
	    s++;
	  }
    }

    /* Last (odd) section spans entire width of window */
    section[s].y = section[s-1].y + sectionDeltaV;
    section[s].x = 0;
}

main (argc, argv)
    int argc;
    char *argv[];
{
    int     i;
    int     buffers;
    int     done;
    int     data_count;
    float   x_diff;
    float   y_diff;
    char   *version;
    long    plane_masks[2];
    long    event_mask;
    unsigned long failures;
    Arg     args[8];
    Widget  toplevel;
    Widget  control;
    Widget  button_draw_text;
    Widget  button_draw_points;
    Widget  button_draw_lines;
    Widget  button_draw_tris;
    Widget  button_draw_pixels;
    Widget  button_change_color;
    Widget  button_rot_ulay;
    Widget  button_undraw_olay;
    Widget  button_reverse_transp;
    Widget  button_quit;
    Widget  popup_shell;
    Widget  popup_shell2;
    Widget  underlay;
    Visual  *default_visual;
    Visual  *ol_visual;
    Screen  *screen_ptr;
    XtAppContext app_context;
    XColor  gray;
    XColor  light_gray;
    XColor  dummy;
    XEvent  event;
    XVisualInfo info;
    XSetWindowAttributes attr;
    XClientMessageEvent *client_message = (XClientMessageEvent*) &event;

    { extern int _Xdebug;
      _Xdebug = 1;
    }

/*
 *  Create the top level shell.
 */
    toplevel = XtAppInitialize (&app_context, 
				"", 
				NULL, 
				0, 
				(Cardinal*)&argc, 
				argv,
				NULL, 
				NULL,
				0);

    dpy = (Display*) XtDisplay (toplevel);

/*
 *  Get the screen number.
 */
    screen = DefaultScreen (dpy);
    root = RootWindow (dpy, screen);

/*
 *  Get the default colormap.
 */
    default_colormap = DefaultColormap (dpy, screen);

/*
 *  Create a popup shell to hold the controls.
 */

    XtSetArg (args[0], XtNx, 100);
    XtSetArg (args[1], XtNy, 100);
    popup_shell = XtCreatePopupShell ("  ",
                                      topLevelShellWidgetClass,
                                      toplevel,
                                      args,
                                      2);  

    control = XtVaCreateManagedWidget ("control",
                                        xmRowColumnWidgetClass,
                                        popup_shell,
					XmNnumColumns, 1,
					XmNorientation, XmVERTICAL,
                                        NULL);
/*
 *  Create the buttons.
 */

    button_draw_text = XtVaCreateManagedWidget ("Draw Text",
                                       xmPushButtonWidgetClass,
                                       control,
                                       XmNalignment, XmALIGNMENT_END,
                                       NULL);
 
    button_draw_points = XtVaCreateManagedWidget ("Draw Points",
                                       xmPushButtonWidgetClass,
                                       control,
                                       XmNalignment, XmALIGNMENT_END,
                                       NULL);

    button_draw_lines = XtVaCreateManagedWidget ("Draw Lines",
                                       xmPushButtonWidgetClass,
                                       control,
                                       XmNalignment, XmALIGNMENT_END,
                                       NULL);
 
    button_draw_tris = XtVaCreateManagedWidget ("Draw Triangles",
                                       xmPushButtonWidgetClass,
                                       control,
                                       XmNalignment, XmALIGNMENT_END,
                                       NULL);
 
 
    button_draw_pixels = XtVaCreateManagedWidget ("Draw Pixels",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

    button_change_color = XtVaCreateManagedWidget ("Change Color",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

    button_reverse_transp = XtVaCreateManagedWidget ("Reverse Transparency",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

    button_rot_ulay = XtVaCreateManagedWidget ("Rotate Underlay",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

    button_undraw_olay = XtVaCreateManagedWidget ("Undraw Overlay",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

    button_quit = XtVaCreateManagedWidget ("       Quit",
                                       xmPushButtonWidgetClass,
                                       control,
                                       NULL);

/*
 *  Attach the callbacks to the buttons.
 */

    XtAddCallback (button_draw_text, XmNactivateCallback, 
		   button_callback_draw_text, NULL);
    XtAddCallback (button_draw_points, XmNactivateCallback, 
		   button_callback_draw_points, NULL);
    XtAddCallback (button_draw_lines, XmNactivateCallback, 
		   button_callback_draw_lines, NULL);
    XtAddCallback (button_draw_tris, XmNactivateCallback, 
		   button_callback_draw_tris, NULL);
    XtAddCallback (button_draw_pixels, XmNactivateCallback, 
		   button_callback_draw_pixels, NULL);
    XtAddCallback (button_change_color, XmNactivateCallback, 
		   button_callback_change_color, NULL);
    XtAddCallback (button_rot_ulay, XmNactivateCallback, 
		   button_callback_rot_ulay, NULL);
    XtAddCallback (button_undraw_olay, XmNactivateCallback, 
		   button_callback_undraw_olay, NULL);
    XtAddCallback (button_reverse_transp, XmNactivateCallback, 
		   button_callback_reverse_transp, NULL);
    XtAddCallback (button_quit, XmNactivateCallback, button_callback_quit, NULL);

/*
 * Pop the shell.
 */

    XtRealizeWidget (toplevel);
    XtPopup (popup_shell, XtGrabNone);


/*
 * Choose the underlay visual and create a colormap.
 */
    ulSelectVisual();
    ulCmapCreate();

    XSync (dpy, FALSE);

/*
 *  Create a popup shell to hold the graphics widget. Specify the visual, 
 *  depth and colormap.
 */
    XtSetArg (args[0], XtNvisual, ulvisinfo->visual);
    XtSetArg (args[1], XtNdepth, depth);
    XtSetArg (args[2], XtNcolormap, ul_colormap);
    XtSetArg (args[3], XtNx, 350);
    XtSetArg (args[4], XtNy, 100);
    popup_shell2 = XtCreatePopupShell ("OGL with SOV Overlay", 
                                       topLevelShellWidgetClass,
                                       toplevel,
                                       args,
                                       5);

/*
 *  Create a "canvas" and attach it to the popup shell. 
 */
    underlay = XtVaCreateManagedWidget ("underlay",
                                        xmDrawingAreaWidgetClass,
                                        popup_shell2, 
                                        XtNwidth,  winWidth,
                                        XtNheight, winHeight,
                                        NULL);

/*
 *  Pop the shell.
 */
    XtRealizeWidget (popup_shell2);
    XtPopup (popup_shell2, XtGrabNone);
    ul_window = (Window) XtWindow (underlay);
 
/*
 * Create the underlay context and make it current.
 * Need to do this before we get the transparent pixel
 */
    ulCtxCreateAndInit();
/*
 *  Create the overlay window and it's context.
 */
    olCreateAndInit();
    olCtxCreateAndInit();

/*
 *  Map the windows.
 */
    XSetWMColormapWindows(dpy, XtWindowOfObject(popup_shell2), &ol_window, 1);
    XMapWindow (dpy, ul_window);
    XMapWindow (dpy, ol_window);
    do {
        XNextEvent (dpy, &event);
    } while (event.type != Expose);

/*
 *  Select input.
 */
    XSelectInput (dpy, ul_window, ExposureMask |
                                         ButtonPressMask |
                                         ButtonReleaseMask |
                                         ButtonMotionMask |
                                         StructureNotifyMask);
/*
 *  Initialize the data.
 */
    reshape(winWidth, winHeight);

    calcSections();
    initFontDlist();

/*
 *  Render the underlay
 */
    ul_traverse ();
    ol_traverse();

/*
 *  Handle the events.
 */
    rotate = FALSE;
    data_count = 0;
    event_mask = ButtonPressMask;
    while (TRUE) {
       XNextEvent (dpy, &event);
       if (event.xany.window == ul_window) {
          switch (event.type) {
             case Expose:
                ul_traverse ();
                ol_traverse ();
		glXWaitGL();
                break;
             case ButtonPress:
		basex = event.xmotion.x;
		basey = event.xmotion.y;
                break;
             case ButtonRelease:
		angleYdelta = 0.0;
		angleXdelta = 0.0;
                break;
             case ConfigureNotify:
                break;
             case MotionNotify:
		angleYdelta = (GLfloat)(event.xmotion.y - basey);
		angleY = angleYdelta;
		if (angleY >= 360.0) {
		    angleY =- 360.0;
		}
		angleXdelta = (GLfloat)(event.xmotion.x - basex);
		angleX = angleXdelta;
		if (angleX >= 360.0) {
		    angleX =- 360.0;
		}
                ul_traverse ();
		glXWaitGL();
		break;
             default:
                XtDispatchEvent (&event);
                break;
          }
       }
       else {
	  if (event.xany.window == ol_window && event.type == Expose)
	     printf("Got expose on overlay\n");
          XtDispatchEvent (&event);
       } 
   }
}


void
olClear ()
{
    glClearIndex((GLfloat)(olColors[olCurColor].bkgdPixel));
    glClear(GL_COLOR_BUFFER_BIT);
}

void
olPointsDraw ()
{
    Point   *pS;
    GLfloat x, y;

    pS = &section[SECTION_POINTS];
    glViewport(pS->x, pS->y, sectionDeltaH, sectionDeltaV);
 
    if (cpv) {
	glBegin(GL_POINTS);
        for (y = -0.8; y <= 0.8; y += 0.1) {
	    for (x = -0.8; x <= 0.8; x += 0.1) {
		glIndexi(olColors[olCurColor].frgdPixel);
		glVertex3f(x, y, 0.0);
	    }
	}
	glEnd();
    } else {
	glIndexi(olColors[olCurColor].frgdPixel);
	glBegin(GL_POINTS);
        for (y = -0.8; y <= 0.8; y += 0.1) {
	    for (x = -0.8; x <= 0.8; x += 0.1) {
		glVertex3f(x, y, 0.0);
	    }
	}
	glEnd();
    }
}

#define ANNOTATION_STRING "Annotation Text"
#define NUM_STRINGS      6

#define RASPOS_INIT_X    0.2
#define RASPOS_INIT_Y    0.2


void
olTextDraw ()
{
    Point *pS;
    int   i, k;
    char  *s;
    int   len = strlen(ANNOTATION_STRING);
    GLfloat rasposX, rasposY;
    GLfloat rasposYdelta = (2.0 - 2 * RASPOS_INIT_Y) / 
                               (GLfloat)NUM_STRINGS;

    glPushMatrix();

    pS = &section[SECTION_TEXT];
    glViewport(pS->x, pS->y, sectionDeltaH, sectionDeltaV);
    glTranslatef(-1.0, -1.0, 0.0);

    glIndexi(olColors[olCurColor].frgdPixel);

    rasposY = RASPOS_INIT_Y;
    for (i = 0; i < NUM_STRINGS; i++, rasposY += rasposYdelta) {
	s = ANNOTATION_STRING;
	rasposX = RASPOS_INIT_X;
	glRasterPos3f(rasposX, rasposY, 0.0);
	for (k = 0; k < len; k++, s++) {
	    glCallList(fontDlBase + (int)*s);
	}
    }

    glPopMatrix();
}

void
olLinesDraw ()
{
    Point *pS;

    pS = &section[SECTION_LINE];
    glViewport(pS->x, pS->y, sectionDeltaH, sectionDeltaV);
 
    if (cpv) {
	glBegin(GL_LINE_STRIP);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.8, -0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.6,  0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.4, -0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.2,  0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.0, -0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.2,  0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.4, -0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.6,  0.8, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.8, -0.8, 0.0);
	glEnd();
    } else {
	glIndexi(olColors[olCurColor].frgdPixel);
	glBegin(GL_LINE_STRIP);
            glVertex3f(-0.8, -0.8, 0.0);
            glVertex3f(-0.6,  0.8, 0.0);
            glVertex3f(-0.4, -0.8, 0.0);
            glVertex3f(-0.2,  0.8, 0.0);
            glVertex3f( 0.0, -0.8, 0.0);
            glVertex3f( 0.2,  0.8, 0.0);
            glVertex3f( 0.4, -0.8, 0.0);
            glVertex3f( 0.6,  0.8, 0.0);
            glVertex3f( 0.8, -0.8, 0.0);
	glEnd();
    }
}

void
olTrisDraw ()
{
    Point *pS;

    pS = &section[SECTION_TRIS];
    glViewport(pS->x, pS->y, sectionDeltaH, sectionDeltaV);
 
    if (cpv) {
	glBegin(GL_TRIANGLES);

	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-1.0,  -1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.75,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.5,  -1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.5,  -1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.25,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.0,  -1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.0,  -1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.25,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.5,  -1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.5,  -1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.75,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 1.0,  -1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-1.0,   1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.75,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.5,   1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.5,   1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.25,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f(-0.0,   1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.0,   1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.25,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.5,   1.0, 0.0);
    
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.5,   1.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 0.75,  0.0, 0.0);
	    glIndexi(olColors[olCurColor].frgdPixel);
            glVertex3f( 1.0,   1.0, 0.0);
     
	glEnd();
    } else {
	glIndexi(olColors[olCurColor].frgdPixel);
	glBegin(GL_TRIANGLES);

            glVertex3f(-1.0,  -1.0, 0.0);
            glVertex3f(-0.75,  0.0, 0.0);
            glVertex3f(-0.5,  -1.0, 0.0);
    
            glVertex3f(-0.5,  -1.0, 0.0);
            glVertex3f(-0.25,  0.0, 0.0);
            glVertex3f(-0.0,  -1.0, 0.0);
    
            glVertex3f( 0.0,  -1.0, 0.0);
            glVertex3f( 0.25,  0.0, 0.0);
            glVertex3f( 0.5,  -1.0, 0.0);
    
            glVertex3f( 0.5,  -1.0, 0.0);
            glVertex3f( 0.75,  0.0, 0.0);
            glVertex3f( 1.0,  -1.0, 0.0);
    
            glVertex3f(-1.0,   1.0, 0.0);
            glVertex3f(-0.75,  0.0, 0.0);
            glVertex3f(-0.5,   1.0, 0.0);
    
            glVertex3f(-0.5,   1.0, 0.0);
            glVertex3f(-0.25,  0.0, 0.0);
            glVertex3f(-0.0,   1.0, 0.0);
    
            glVertex3f( 0.0,   1.0, 0.0);
            glVertex3f( 0.25,  0.0, 0.0);
            glVertex3f( 0.5,   1.0, 0.0);
    
            glVertex3f( 0.5,   1.0, 0.0);
            glVertex3f( 0.75,  0.0, 0.0);
            glVertex3f( 1.0,   1.0, 0.0);
     
	glEnd();
    }
}

unsigned char *image = NULL;

#define DRAW_PIX_X_OFFSET 100

void
olDrawPixDraw ()
{
    Point   *pS;
    int     i, k;
    int     w = winWidth - 2 * DRAW_PIX_X_OFFSET;
    int     h = (int) sectionDeltaV;
    unsigned char *pImage;
    int     drawBkgd;

    glPushMatrix();

    pS = &section[SECTION_DRAWPIX];
    glViewport(pS->x, pS->y, sectionDeltaH, sectionDeltaV);

    if (!image) {
	image = (unsigned char *) malloc(w * h *
					 sizeof(unsigned char));
    }

    pImage = image;
    drawBkgd = 0;
    for (i = 0; i < h; i++) {
	if ((i % 4) == 0) {
	    drawBkgd = ~drawBkgd;
	}
	for (k = 0; k < w; k++) {
	    if ((k % 4) == 0) {
		drawBkgd = ~drawBkgd;
	    }
	    if (drawBkgd) {
		*pImage++ = drawPixBkgd.pixel;
	    } else {
		*pImage++ = olColors[olCurColor].frgdPixel;
	    }
	}
    }

    glTranslatef(0.0, -1.0, 0.0);
    glRasterPos3f (0.0, 0.0, 0.0);
 
    glDrawPixels (w, h, GL_COLOR_INDEX,
		  GL_UNSIGNED_BYTE, (GLvoid*)image);

    glPopMatrix();
}

void ol_traverse ()
{
    glXMakeCurrent(dpy, ol_window, olctx);

    if (clearOverlayOnTraverse)
	olClear();

    if (textOn) {
	olTextDraw();
    }
    if (pointsOn) {
	olPointsDraw();
    }
    if (linesOn) {
	olLinesDraw();
    }
    if (trisOn) {
	olTrisDraw();
    }
    if (drawPixOn) {
	olDrawPixDraw();
    }
}


/*
 *      DrawTorus:  Draw a torus shape.
 */
void
DrawTorus(float rc, int numc, float rt, int numt)
{
    int         i, j, k;
    double      s, t, x, y, z, twopi;


    twopi = 2 * M_PI;
    for (i = 0; i < numc; i++) {
        glBegin(GL_QUAD_STRIP);
        for (j = 0; j <= (numt); j++) {
            for (k = 1; k >= 0; k--) {
                s = (i + k) % numc + 0.5;
                t = j % numt;

                x = cos(t * twopi / numt) * cos(s * twopi / numc);
                y = sin(t * twopi / numt) * cos(s * twopi / numc);
                z = sin(s * twopi / numc);
                glNormal3f(x, y, z);
                x = (rt + rc * cos(s * twopi / numc)) * cos(t * twopi / numt);
                y = (rt + rc * cos(s * twopi / numc)) * sin(t * twopi / numt);
                z = rc * sin(s * twopi / numc);
                glVertex3f(x, y, z);
            }
        }
        glEnd();
    }
}

typedef struct viewpt_struct {
    GLfloat x;
    GLfloat y;
    GLfloat z;
} Viewpt;

static Viewpt viewpt = {0.0, 0.0, 5.0};

void ul_traverse ()
{
    GLfloat mat_ambdiff[4] = {0.8, 0.8, 0.0, 1.0};
    GLfloat mat_specular[4] = {0.1, 0.0, 0.0, 1.0};
    
    glXMakeCurrent(dpy, ul_window, ulctx);

    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(-viewpt.x, -viewpt.y, -viewpt.z);
    glScalef(1.5, 1.5, 1.5);
    glRotatef(angleY, 1.0, 0.0, 0.0);
    glRotatef(angleX, 0.0, 1.0, 0.0);

    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_ambdiff);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);

    DrawTorus(0.50, 6, 1.80, 25);

    if (dbuf) {
	glXSwapBuffers(dpy, ul_window);
    }
}

void button_callback_draw_text (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
{
    glXMakeCurrent(dpy, ol_window, olctx);
    olTextDraw();
    glXWaitGL();

    textOn = 1;
}

void button_callback_draw_points (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
{
    glXMakeCurrent(dpy, ol_window, olctx);
    olPointsDraw();
    glXWaitGL();

    pointsOn = 1;
}

void button_callback_draw_lines (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
{
    glXMakeCurrent(dpy, ol_window, olctx);
    olLinesDraw();
    glXWaitGL();

    linesOn = 1;
}
 
void button_callback_draw_tris (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
    glXMakeCurrent(dpy, ol_window, olctx);
    olTrisDraw();
    glXWaitGL();

    trisOn = 1;
}

void button_callback_change_color (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
    olCurColor++;
    if (olColors[olCurColor].frgd == NOCOLOR) {
	olCurColor = 0;
    }

    ol_traverse();
    glXWaitGL();
}

void button_callback_rot_ulay (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
   angleX += 36.0;
   if (angleX >= 360.0)
       angleX =- 360.0;
   angleY += 36.0;
   if (angleY >= 360.0)
       angleY =- 360.0;

   ul_traverse ();
   glXWaitGL();
}

void button_callback_undraw_olay (w, tag, call_data)
 
   Widget w;
   char *tag;
   caddr_t call_data;
{
    int save = olCurColor;
    if (save != transparentForeground) {
	olCurColor = transparentForeground;
	clearOverlayOnTraverse = 0;
	ol_traverse();
	clearOverlayOnTraverse = 1;
    } else {
	glXMakeCurrent(dpy, ol_window, olctx);
	olClear();
	textOn = pointsOn = linesOn = trisOn = drawPixOn = 0;
    }
    olCurColor = save;

    glXWaitGL();
}

void button_callback_reverse_transp (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
    int i, tmp;
    
    i = 0;
    while (1) {
	if (olColors[i].frgd == NOCOLOR) {
	    break;
	}
	tmp = olColors[i].frgdPixel;
	olColors[i].frgdPixel = olColors[i].bkgdPixel;
	olColors[i].bkgdPixel = tmp;

	if (olColors[i].frgdPixel == pixTp)
            transparentForeground = olCurColor;

	i++;
    }
    ol_traverse ();
    glXWaitGL();
}

void button_callback_draw_pixels (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
    glXMakeCurrent(dpy, ol_window, olctx);
    olDrawPixDraw();

    drawPixOn = 1;
    glXWaitGL();
}

void button_callback_quit (w, client_data, call_data)
   Widget w;
   XtPointer client_data;
   XtPointer call_data;
{
    exit (0);
}
