#pragma ident "@(#)ogl_mda_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 two extensions
 * GL_SUN_multi_draw_arrays and the GL_EXT_multi_draw_arrays.
 *
 * This program draws a sequence of three circles four times using
 *
 *     glMultiDrawArraysSUN()
 *     glMultiDrawElementsSUN()
 *     glMultiDrawArraysEXT()
 *     glMultiDrawElementsEXT()
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.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 = 300;
int height = 400;

Bool hasExtension = False;

GLfloat vertex[306][3];
GLint first[3];
GLsizei count[3];
GLuint *indices[3], index[306];

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;
	GLdouble PI = 3.141596;
	GLdouble angle;
	int	i, j;

	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_EXT_multi_draw_arrays",
                extstr);
            if (!hasExtension) {
                fprintf(stderr, "GL_EXT_multi_draw_arrays extension not supported\n");
                (void) exit(1);
            }
            hasExtension = checkExtension("GL_SUN_multi_draw_arrays", extstr);
            if (!hasExtension) {
                fprintf(stderr, "GL_SUN_multi_draw_arrays extension no supported\n");
		(void) exit(1);
            }
        }
        else {
	    fprintf(stderr, "GL_EXT_multi_draw_arrays extension and GL_SUN_multi_draw_arrays 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, 300.0, 0.0, 400.0, -1.0, 1.0);

	/*
	** First triangle fan
	*/
	first[0] = 0;   /* the start index */
	count[0] = 102; /* the number of vertices */
	vertex[0][0] = 50.0;
	vertex[0][1] = 50.0;
	vertex[0][2] = -0.5;
	j = 1;
	for (i = 0; i <= 100; i++) {
	  angle = 2 * PI *  i/100.0;
	  vertex[j][0] = 50.0 + cos(angle)*50.0;
	  vertex[j][1] = 50.0 + sin(angle)*50.0;
	  vertex[j][2] = -0.5;
	  j++;
	} 
 
	/*
	** Second triangle fan
	*/
	first[1] = 102; /* the start index */
	count[1] = 102; /* the number of vertices */
	vertex[102][0] = 150.0;
	vertex[102][1] = 50.0;
	vertex[102][2] = -0.5;
	j = 103;
	for (i = 0; i <= 100; i++) {
	  angle = 2 * PI *  i/100.0;
	  vertex[j][0] = 150.0 + cos(angle)*50.0;
	  vertex[j][1] = 50.0 + sin(angle)*50.0;
	  vertex[j][2] = -0.5;
	  j++;
	} 

	/*
	** Third triangle fan
	*/
	first[2] = 204; /* the start index */
	count[2] = 102; /* the number of vertices */
	vertex[204][0] = 250.0;
	vertex[204][1] = 50.0;
	vertex[204][2] = -0.5;
	j = 205;
	for (i = 0; i <= 100; i++) {
	  angle = 2 * PI *  i/100.0;
	  vertex[j][0] = 250.0 + cos(angle)*50.0;
	  vertex[j][1] = 50.0 + sin(angle)*50.0;
	  vertex[j][2] = -0.5;
	  j++;
	} 

	glInterleavedArrays(GL_V3F, 3 * sizeof(GL_FLOAT), vertex);

	/*
	** Set up the indices argument for glMultiDrawElementsSUN() and
	** glMultiDrawElementsEXT().
	*/
	for (i = 0; i < 306; i++) index[i] = i;
	indices[0] = &index[0];
	indices[1] = &index[102];
	indices[2] = &index[204];
        
	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()
{
        glClear(GL_COLOR_BUFFER_BIT);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        /* Draw three red circles */
        glColor3f(1.0, 0.0, 0.0);
        glMultiDrawArraysSUN(GL_TRIANGLE_FAN, first, count, 3);

        glTranslatef(0.0, 100.0, 0.0);

        /* Draw three green circles */
        glColor3f(0.0, 1.0, 0.0);
        glMultiDrawElementsSUN(GL_TRIANGLE_FAN, count, GL_UNSIGNED_INT,
                               (const GLvoid **) indices, 3);

        glTranslatef(0.0, 100.0, 0.0);

        /* Draw three blue circles */
        glColor3f(0.0, 0.0, 1.0);
        glMultiDrawArraysEXT(GL_TRIANGLE_FAN, first, count, 3);

        glTranslatef(0.0, 100.0, 0.0);

        /* Draw three white circles */
        glColor3f(1.0, 1.0, 1.0);
        glMultiDrawElementsEXT(GL_TRIANGLE_FAN, count, GL_UNSIGNED_INT,
                               (const GLvoid **) indices, 3);

	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, 300, 400, 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, "MultiDrawArrays Example");

	return window;
}
