#pragma ident "@(#)ogl_constdata_ex1.c	1.1 98/08/03   SMI"
/*
 *   ----------------------------------------------------------------- 
 *          Copyright (C) 1998  Sun Microsystems, Inc
 *                      All rights reserved. 
 *            Notice of copyright on this source code 
 *            product does not indicate publication. 
 *   
 *                    RESTRICTED RIGHTS LEGEND: 
 *   Use, duplication, or disclosure by the Government is subject 
 *   to restrictions as set forth in subparagraph (c)(1)(ii) of 
 *   the Rights in Technical Data and Computer Software clause at 
 *   DFARS 52.227-7013 and in similar clauses in the FAR and NASA 
 *   FAR Supplement. 
 *   ----------------------------------------------------------------- 
 */

/*
 * Simple example program that demonstrates the use of the GL_SUNX_constant_data
 * extension.
 *
 * This program draws a red and green checkerboard at the lower left corner of
 * the window, and a blue and white checkerboard at the upper right corner of
 * the window.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <GL/glx.h>
#include <GL/gl.h>

static Bool verbose = False;

static void drawGL();
static Window createWindow(Display *dpy, int screen, XVisualInfo *vi);
static XVisualInfo * findVisual(Display *dpy, int screen, Bool *doubleBuffered);


Bool	doDirect = True;
int width = 500;
int height = 500;

Bool hasExtension = False;

#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImageABGR[checkImageWidth][checkImageHeight][4];

static GLboolean
checkExtension(char *extName, const char *extString)
{
    char *p = (char*) extString;
    int  extNameLen = strlen(extName);
    char *end = p + strlen(p);

    while (p < end) {
	int n = strcspn(p, " ");
	if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
	    return GL_TRUE;
	}
	p += n + 1;
    }
    return GL_FALSE;
}

int
main(int argc)
{
	Display *dpy;
	int	screen;
	Window	window;
	int	dummy;
	int	done = False;
	Bool	doubleBuffered;
	XVisualInfo *vi;
	GLXContext context;
	GC	gc;
	char	*extstr;

	if (argc > 1) 
	    doDirect = False;
	dpy = XOpenDisplay(NULL);
	if (dpy == NULL) {
	    fprintf(stderr, "can't open X display\n");
	    return (1);
	}
	screen = DefaultScreen(dpy);

	if (!glXQueryExtension(dpy, &dummy, &dummy)) {
	    fprintf(stderr, "server doesn't support GLX Extension\n");
	    return (1);
	}

	vi = findVisual(dpy, screen, &doubleBuffered);
	if (vi == NULL)
	    return 1;

	window = createWindow(dpy, screen, vi);

	context = glXCreateContext(dpy, vi, NULL, doDirect);
	doDirect = glXIsDirect(dpy, context);

	if (context == NULL) {
	    fprintf(stderr, "can't create context\n");
	    return (1);
	}

	XFree(vi);

	if (!glXMakeCurrent(dpy, window, context)) {
	    fprintf(stderr, "glXMakeCurrent failed\n");
	    return (1);
	}

	extstr = (char *) glGetString(GL_EXTENSIONS);
        if (extstr != NULL) {
            hasExtension = checkExtension("GL_SUNX_constant_data", extstr);
            if (!hasExtension) {
                fprintf(stderr, "GL_SUNX_constant_data extension not supported\n");
                (void) exit(1);
            }
            hasExtension = checkExtension("GL_EXT_abgr", extstr);
            if (!hasExtension) {
                fprintf(stderr, "GL_EXT_abgr extension not supported. This example needs this extension.\n");
                (void) exit(1);
            }
        }
        else {
	    fprintf(stderr, "GL_SUNX_constant_data extension not supported\n");
	    (void) exit(1);
	}
        if (verbose) {

            printf("GLX Client Strings\n");
            printf("\tVendor: %s\n\tVersion: %s\n\tExtensions: %s\n\n",
                    glXGetClientString(dpy, GLX_VENDOR),
                    glXGetClientString(dpy, GLX_VERSION),
                    glXGetClientString(dpy, GLX_EXTENSIONS));

            printf("GLX Server Strings\n");
            printf("\tVendor: %s\n\tVersion: %s\n\tExtensions: %s\n\n",
                    glXQueryServerString(dpy, screen, GLX_VENDOR),
                    glXQueryServerString(dpy, screen, GLX_VERSION),
                    glXQueryServerString(dpy, screen, GLX_EXTENSIONS));

            if (extstr == NULL)
                extstr = "None";

            printf("GL Extension String: %s\n\n",  extstr);
        }

	if (verbose) {
	    printf("\nGL Strings:\n");
	    printf("\tVendor: %s\n\tRenderer: %s\n\tVersion: %s\n\tExtensions: %s\n\n",
			glGetString(GL_VENDOR),
			glGetString(GL_RENDERER),
			glGetString(GL_VERSION),
			glGetString(GL_EXTENSIONS));
	}

	glClearColor(0.0, 0, 0, 0);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity ();
        glOrtho(0.0, 500.0, 0.0, 500.0, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity ();

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	/* Tell OpenGL that it can use the pixel data specified by the application
	   internally without making a second copy. */
	glPixelStorei(GL_UNPACK_CONSTANT_DATA_SUNX, GL_TRUE);

	/* Set up texture parameter */
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
	glEnable(GL_TEXTURE_2D);

	if (argc > 1) {
	    glDrawBuffer(GL_FRONT);
	    doubleBuffered = False;
	}

	while(!done) {
	    XEvent	report;
	    glXWaitGL();

	    XNextEvent(dpy, &report);
	    switch (report.type) {
	    case ConfigureNotify:
		width = report.xconfigure.width;
		height = report.xconfigure.height;
		glViewport(0, 0, width, height);
		break;
	    case Expose:
                drawGL();
                if (doubleBuffered)
                    glXSwapBuffers(dpy, window);
                else
                    glFlush();
		break;
	    case ClientMessage:
		done = True;
		break;
	    default:
		break;
	    }
	}

	glXDestroyContext(dpy, context);
	XSync(dpy, 0);
	return (0);
}

static void
drawGL()
{
    GLint is_const;
    int   i, j;

    glClear(GL_COLOR_BUFFER_BIT);

    /* Make a red and green checkerboard texture */
    for (i = 0; i < checkImageWidth; i++) {
        for (j = 0; j < checkImageHeight; j++) {
            if (((i&0x8)==0) ^ ((j&0x8)==0)) {
                checkImageABGR[i][j][0] = (GLubyte) 255;
                checkImageABGR[i][j][1] = (GLubyte) 0;
                checkImageABGR[i][j][2] = (GLubyte) 0;
                checkImageABGR[i][j][3] = (GLubyte) 255;
            }
            else {
                checkImageABGR[i][j][0] = (GLubyte) 255;
                checkImageABGR[i][j][1] = (GLubyte) 0;
                checkImageABGR[i][j][2] = (GLubyte) 255;
                checkImageABGR[i][j][3] = (GLubyte) 0;
            }
        }
    }    

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0,
                 GL_ABGR_EXT, GL_UNSIGNED_BYTE, checkImageABGR);

    /* Draw a red and green checkerboard */
    glBegin(GL_QUADS);
      glTexCoord2f(0.0, 0.0);   glVertex3f(50.0, 50.0, 0.0);
      glTexCoord2f(0.0, 1.0);   glVertex3f(50.0, 200.0, 0.0);
      glTexCoord2f(1.0, 1.0);   glVertex3f(200.0, 200.0, 0.0);
      glTexCoord2f(1.0, 0.0);   glVertex3f(200.0, 50.0, 0.0);
    glEnd();

    /*
     If  interested,  an  application  could inquire the constant
     nature of the texture data using glGetTexLevelParameter*()
     after the texture has  been  used for rendering.
    */
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
                             GL_TEXTURE_CONSTANT_DATA_SUNX, &is_const);
    if ( is_const == GL_TRUE )
        printf("The red and green checkerboard texture data is constant\n");
    else
        printf("The red and green checkerboard texture data isn't constant\n");

    /*
     Before the application changes a part or all of  the  texture
     image  that  has been specified as a constant texture image,
     it is necessary to call glFinishTextureSUNX to  ensure  that
     the OpenGL library  has  completed  all  its  processing  with the
     currently  specified  constant  texture  image.
    */
    glFinishTextureSUNX();

    /* Make a blue and white checkerboard texture */
    for (i = 0; i < checkImageWidth; i++) {
        for (j = 0; j < checkImageHeight; j++) {
            if (((i&0x8)==0) ^ ((j&0x8)==0)) {
                checkImageABGR[i][j][0] = (GLubyte) 255;
                checkImageABGR[i][j][1] = (GLubyte) 255;
                checkImageABGR[i][j][2] = (GLubyte) 0;
                checkImageABGR[i][j][3] = (GLubyte) 0;
            }   
            else {
                checkImageABGR[i][j][0] = (GLubyte) 255;
                checkImageABGR[i][j][1] = (GLubyte) 255;
                checkImageABGR[i][j][2] = (GLubyte) 255;
                checkImageABGR[i][j][3] = (GLubyte) 255;
            }   
        }
    }    
 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0,
                 GL_ABGR_EXT, GL_UNSIGNED_BYTE, checkImageABGR);

    /* Draw a blue and white checkerboard */
    glBegin(GL_QUADS);
      glTexCoord2f(0.0, 0.0);   glVertex3f(300.0, 300.0, 0.0);
      glTexCoord2f(0.0, 1.0);   glVertex3f(300.0, 450.0, 0.0);
      glTexCoord2f(1.0, 1.0);   glVertex3f(450.0, 450.0, 0.0);
      glTexCoord2f(1.0, 0.0);   glVertex3f(450.0, 300.0, 0.0);
    glEnd();
      
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
                             GL_TEXTURE_CONSTANT_DATA_SUNX, &is_const);
    if ( is_const == GL_TRUE )
        printf("The blue and white checkerboard texture data is constant\n");
    else
        printf("The blue and white checkerboard texture data isn't constant\n");
 
    glFinishTextureSUNX();

    glFlush();
}

static XVisualInfo *
findVisual(Display *dpy, int screen, Bool *doubleBuffered)
{
	/*
	 * Find a GLX Visual to use.
	 *   Order of preference
	 *       24 bit mono double buffered
	 *       24 bit stereo double buffered
	 *       24 bit single buffered
	 *       any depth double buffered
	 *       any depth single buffered
	 */
    int dblBuf24[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
		    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None };
    int dblStereo24[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_STEREO, 
		    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None };
    int snglBuf24[] = { GLX_RGBA, 
		    GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None };
    int dblBuf[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
    int snglBuf[] = { GLX_RGBA, None };

    XVisualInfo *vi = NULL;
    int stereo = False;

    vi = glXChooseVisual(dpy, screen, dblBuf24);
    if (vi != NULL) {
	*doubleBuffered = True;
    } else {
      vi = glXChooseVisual(dpy, screen, dblStereo24);
      if (vi !=NULL) {
	  *doubleBuffered = True;
	  stereo = True;
      } else {
	vi = glXChooseVisual(dpy, screen, snglBuf24);
	if (vi !=NULL) {
	    *doubleBuffered = False;
	} else {
	    vi = glXChooseVisual(dpy, screen, dblBuf);
	    if (vi != NULL) {
		*doubleBuffered = True;
	    } else {
		vi = glXChooseVisual(dpy, screen, snglBuf);
		if (vi ==NULL) {
		    fprintf(stderr, "can't find visual\n");
		} else {
		    *doubleBuffered = False;
		}
	    }
	}
      }
    }

    if ((vi != NULL) && verbose) {
	int buffer_size;
	Bool db;
	int zbs;
	double gamma;

	(void) XSolarisGetVisualGamma(dpy, screen, vi->visual, &gamma);
	
	glXGetConfig(dpy, vi, GLX_BUFFER_SIZE, &buffer_size);
	glXGetConfig(dpy, vi, GLX_DOUBLEBUFFER, &db);
	glXGetConfig(dpy, vi, GLX_DEPTH_SIZE, &zbs);
	fprintf(stderr, 
	    "Using Visual %d, Buffer Size=%d, %sbuffered, Depth Buffer Size=%d\n\tGamma=%f\n",
	    vi->visualid, 
	    buffer_size, 
	    db ? "Double-" : "Single-",
	    zbs,
	    gamma);

    }	

    return vi;
}


static Window
createWindow(Display *dpy, int screen, XVisualInfo *vi)
{
	XSetWindowAttributes attributes;
	unsigned long valuemask = 0;
	Window root = RootWindow(dpy, screen);
	Atom	delete_window_atom=XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
	Window  window;

	if (vi->visual != DefaultVisual(dpy, screen)) {
	    attributes.colormap = XCreateColormap(dpy, root, 
				vi->visual, AllocNone);
	    valuemask = CWColormap;
	}

	valuemask |= CWBorderPixel | CWBackPixel;
	attributes.border_pixel = 0;
	attributes.background_pixel = 0;
	window = XCreateWindow(dpy, root, 0, 0, 500, 500, 0, 
			vi->depth, CopyFromParent, vi->visual,
			valuemask, &attributes);

	XSelectInput(dpy, window, ExposureMask|StructureNotifyMask);

	XMapWindow(dpy, window);

	XSetWMProtocols(dpy, window, &delete_window_atom, 1);
	XStoreName(dpy, window, "Constant Data Example");

	return window;
}
