/* $XFree86: xc/lib/GL/glx/glxcmds.c,v 1.15 2001/04/07 01:39:39 dawes Exp $ */
/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
** 
** http://oss.sgi.com/projects/FreeB
** 
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
** 
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
** 
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
**
*/

#include "packsingle.h"
#include "glxclient.h"
#include <extutil.h>
#include <Xext.h>
#include <string.h>
#include "glapi.h"
#ifdef GLX_DIRECT_RENDERING
#include "indirect_init.h"
#endif

static const char __glXGLClientExtensions[] = 
			"GL_ARB_multitexture "
			"GL_ARB_imaging "
			"GL_EXT_abgr "
			"GL_EXT_blend_color "
			"GL_EXT_blend_minmax "
			"GL_EXT_blend_subtract "
			;

static const char __glXGLXClientVendorName[] = "SGI";
static const char __glXGLXClientVersion[] = "1.2";
static const char __glXGLXClientExtensions[] = 
			"GLX_EXT_visual_info "
			"GLX_EXT_visual_rating "
			"GLX_EXT_import_context "
			;

/*
** Create a new context.
*/
static
GLXContext CreateContext(Display *dpy, XVisualInfo *vis,
				GLXContext shareList, 
				Bool allowDirect, GLXContextID contextID)
{
    xGLXCreateContextReq *req;
    GLXContext gc;
    int bufSize = XMaxRequestSize(dpy) * 4;
    CARD8 opcode;
#ifdef GLX_DIRECT_RENDERING
    __GLXdisplayPrivate *priv;
#endif

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return NULL;
    }

    /* Allocate our context record */
    gc = (GLXContext) Xmalloc(sizeof(struct __GLXcontextRec));
    if (!gc) {
	/* Out of memory */
	return NULL;
    }
    memset(gc, 0, sizeof(struct __GLXcontextRec));

    /* Allocate transport buffer */
    gc->buf = (GLubyte *) Xmalloc(bufSize);
    if (!gc->buf) {
	Xfree(gc);
	return NULL;
    }
    gc->bufSize = bufSize;

    /* Fill in the new context */
    gc->renderMode = GL_RENDER;

    gc->state.storePack.alignment = 4;
    gc->state.storeUnpack.alignment = 4;

    __glXInitVertexArrayState(gc);

    gc->attributes.stackPointer = &gc->attributes.stack[0];

    /*
    ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
    ** Other code uses the fastImageUnpack bit, but it is never set
    ** to GL_TRUE.
    */
    gc->fastImageUnpack = GL_FALSE;
    gc->fillImage = __glFillImage;
    gc->isDirect = GL_FALSE;
    gc->pc = gc->buf;
    gc->bufEnd = gc->buf + bufSize;
    if (__glXDebug) {
	/*
	** Set limit register so that there will be one command per packet
	*/
	gc->limit = gc->buf;
    } else {
	gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
    }
    gc->createDpy = dpy;
    gc->majorOpcode = opcode;

    /*
    ** Constrain the maximum drawing command size allowed to be
    ** transfered using the X_GLXRender protocol request.  First
    ** constrain by a software limit, then constrain by the protocl
    ** limit.
    */
    if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
        bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
    }
    if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
        bufSize = __GLX_MAX_RENDER_CMD_SIZE;
    }
    gc->maxSmallRenderCommandSize = bufSize;


    if (None == contextID) {
#ifdef GLX_DIRECT_RENDERING
	/*
	** Create the direct rendering context, if requested and
	** available.
	*/
	priv = __glXInitialize(dpy);
	if (allowDirect && priv->driDisplay.private) {
	    __GLXscreenConfigs *psc = &priv->screenConfigs[vis->screen];
	    if (psc && psc->driScreen.private) {
		void *shared = (shareList ?
				shareList->driContext.private : NULL);
		gc->driContext.private =
		    (*psc->driScreen.createContext)(dpy, vis, shared,
						    &gc->driContext);
		if (gc->driContext.private) {
		    gc->isDirect = GL_TRUE;
		    gc->screen = vis->screen;
		    gc->vid = vis->visualid;
		}
	    }
	}
#endif

	/* Send the glXCreateContext request */
	LockDisplay(dpy);
	GetReq(GLXCreateContext,req);
	req->reqType = gc->majorOpcode;
	req->glxCode = X_GLXCreateContext;
	req->context = gc->xid = XAllocID(dpy);
	req->visual = vis->visualid;
	req->screen = vis->screen;
	req->shareList = shareList ? shareList->xid : None;
	req->isDirect = gc->isDirect;
	UnlockDisplay(dpy);
	SyncHandle();
	gc->imported = GL_FALSE;
    }
    else {
	gc->xid = contextID;
	gc->imported = GL_TRUE;
    }

    return gc;
}

GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
			    GLXContext shareList, Bool allowDirect)
{
    return CreateContext(dpy, vis, shareList, allowDirect, None);
}

void __glXFreeContext(__GLXcontext *gc)
{
    if (gc->vendor) XFree((char *) gc->vendor);
    if (gc->renderer) XFree((char *) gc->renderer);
    if (gc->version) XFree((char *) gc->version);
    if (gc->extensions) XFree((char *) gc->extensions);
    __glFreeAttributeState(gc);
    XFree((char *) gc->buf);
    XFree((char *) gc);
    
}

/*
** Destroy the named context
*/
static void 
DestroyContext(Display *dpy, GLXContext gc)
{
    xGLXDestroyContextReq *req;
    GLXContextID xid;
    CARD8 opcode;
    GLboolean imported;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode || !gc) {
	return;
    }

    __glXLock();
    xid = gc->xid;
    imported = gc->imported;
    gc->xid = None;

#ifdef GLX_DIRECT_RENDERING
    /* Destroy the direct rendering context */
    if (gc->isDirect) {
	if (gc->driContext.private) {
	    (*gc->driContext.destroyContext)(dpy, gc->screen,
					     gc->driContext.private);
	    gc->driContext.private = NULL;
	}
    }
#endif

    if (gc->currentDpy) {
	/* Have to free later cuz it's in use now */
	__glXUnlock();
    } else {
	/* Destroy the handle if not current to anybody */
	__glXUnlock();
	__glXFreeContext(gc);
    }

    if (!imported) {
	/* 
	** This dpy also created the server side part of the context.
	** Send the glXDestroyContext request.
	*/
	LockDisplay(dpy);
	GetReq(GLXDestroyContext,req);
	req->reqType = opcode;
	req->glxCode = X_GLXDestroyContext;
	req->context = xid;
	UnlockDisplay(dpy);
	SyncHandle();
    }
}
void glXDestroyContext(Display *dpy, GLXContext gc)
{
    DestroyContext(dpy, gc);
}

/*
** Return the major and minor version #s for the GLX extension
*/
Bool glXQueryVersion(Display *dpy, int *major, int *minor)
{
    __GLXdisplayPrivate *priv;

    /* Init the extension.  This fetches the major and minor version. */
    priv = __glXInitialize(dpy);
    if (!priv) return GL_FALSE;

    if (major) *major = priv->majorVersion;
    if (minor) *minor = priv->minorVersion;
    return GL_TRUE;
}

/*
** Query the existance of the GLX extension
*/
Bool glXQueryExtension(Display *dpy, int *errorBase, int *eventBase)
{
    int major_op, erb, evb;
    Bool rv;

    rv = XQueryExtension(dpy, GLX_EXTENSION_NAME, &major_op, &evb, &erb);
    if (rv) {
	if (errorBase) *errorBase = erb;
	if (eventBase) *eventBase = evb;
    }
    return rv;
}

/*
** Put a barrier in the token stream that forces the GL to finish its
** work before X can proceed.
*/
void glXWaitGL(void)
{
    xGLXWaitGLReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
/* This bit of ugliness unwraps the glFinish function */
#ifdef glFinish
#undef glFinish
#endif
	glFinish();
	return;
    }
#endif

    /* Send the glXWaitGL request */
    LockDisplay(dpy);
    GetReq(GLXWaitGL,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitGL;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

/*
** Put a barrier in the token stream that forces X to finish its
** work before GL can proceed.
*/
void glXWaitX(void)
{
    xGLXWaitXReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	XSync(dpy, False);
	return;
    }
#endif

    /*
    ** Send the glXWaitX request.
    */
    LockDisplay(dpy);
    GetReq(GLXWaitX,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitX;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

void glXUseXFont(Font font, int first, int count, int listBase)
{
    xGLXUseXFontReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    (void) __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
      DRI_glXUseXFont(font, first, count, listBase);
      return;
    }
#endif

    /* Send the glXUseFont request */
    LockDisplay(dpy);
    GetReq(GLXUseXFont,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXUseXFont;
    req->contextTag = gc->currentContextTag;
    req->font = font;
    req->first = first;
    req->count = count;
    req->listBase = listBase;
    UnlockDisplay(dpy);
    SyncHandle();
}

/************************************************************************/

/*
** Copy the source context to the destination context using the
** attribute "mask".
*/
void glXCopyContext(Display *dpy, GLXContext source, GLXContext dest,
		    unsigned long mask)
{
    xGLXCopyContextReq *req;
    GLXContext gc = __glXGetCurrentContext();
    GLXContextTag tag;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	/* NOT_DONE: This does not work yet */
    }
#endif

    /*
    ** If the source is the current context, send its tag so that the context
    ** can be flushed before the copy.
    */
    if (source == gc && dpy == gc->currentDpy) {
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXCopyContext request */
    LockDisplay(dpy);
    GetReq(GLXCopyContext,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCopyContext;
    req->source = source ? source->xid : None;
    req->dest = dest ? dest->xid : None;
    req->mask = mask;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
}


/*
** Return GL_TRUE if the context is direct rendering or not.
*/
static Bool __glXIsDirect(Display *dpy, GLXContextID contextID)
{
    xGLXIsDirectReq *req;
    xGLXIsDirectReply reply;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return GL_FALSE;
    }

    /* Send the glXIsDirect request */
    LockDisplay(dpy);
    GetReq(GLXIsDirect,req);
    req->reqType = opcode;
    req->glxCode = X_GLXIsDirect;
    req->context = contextID;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);
    SyncHandle();

    return reply.isDirect;
}

Bool glXIsDirect(Display *dpy, GLXContext gc)
{
    if (!gc) {
	return GL_FALSE;
#ifdef GLX_DIRECT_RENDERING
    } else if (gc->isDirect) {
	return GL_TRUE;
#endif
    }
    return __glXIsDirect(dpy, gc->xid);
}

GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *vis, Pixmap pixmap)
{
    xGLXCreateGLXPixmapReq *req;
    GLXPixmap xid;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return None;
    }

    /* Send the glXCreateGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXCreateGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCreateGLXPixmap;
    req->screen = vis->screen;
    req->visual = vis->visualid;
    req->pixmap = pixmap;
    req->glxpixmap = xid = XAllocID(dpy);
    UnlockDisplay(dpy);
    SyncHandle();
    return xid;
}

/*
** Destroy the named pixmap
*/
void glXDestroyGLXPixmap(Display *dpy, GLXPixmap glxpixmap)
{
    xGLXDestroyGLXPixmapReq *req;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }
    
    /* Send the glXDestroyGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXDestroyGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXDestroyGLXPixmap;
    req->glxpixmap = glxpixmap;
    UnlockDisplay(dpy);
    SyncHandle();
}

void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
{
    xGLXSwapBuffersReq *req;
    GLXContext gc = __glXGetCurrentContext();
    GLXContextTag tag;
    CARD8 opcode;
#ifdef GLX_DIRECT_RENDERING
    __GLXdisplayPrivate *priv;
    __DRIdrawable *pdraw;

#if defined(XTHREADS)
    xmutex_lock(&__glXSwapBuffersMutex);
#endif

    priv = __glXInitialize(dpy);
    if (priv->driDisplay.private) {
	__GLXscreenConfigs *psc = &priv->screenConfigs[gc->screen];
	if (psc && psc->driScreen.private) {
	    /*
	    ** getDrawable returning NULL implies that the drawable is
	    ** not bound to a direct rendering context.
	    */
	    pdraw = (*psc->driScreen.getDrawable)(dpy, drawable,
						  psc->driScreen.private);
	    if (pdraw) {
		(*pdraw->swapBuffers)(dpy, pdraw->private);
#if defined(XTHREADS)
                xmutex_unlock(&__glXSwapBuffersMutex);
#endif
		return;
	    }
	}
    }
#endif

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS)
        xmutex_unlock(&__glXSwapBuffersMutex);
#endif
	return;
    }

    /*
    ** The calling thread may or may not have a current context.  If it
    ** does, send the context tag so the server can do a flush.
    */
    if ((dpy == gc->currentDpy) && (drawable == gc->currentDrawable)) {
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXSwapBuffers request */
    LockDisplay(dpy);
    GetReq(GLXSwapBuffers,req);
    req->reqType = opcode;
    req->glxCode = X_GLXSwapBuffers;
    req->drawable = drawable;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
    XFlush(dpy);
#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS)
    xmutex_unlock(&__glXSwapBuffersMutex);
#endif
}

/*
** Return configuration information for the given display, screen and
** visual combination.
*/
int glXGetConfig(Display *dpy, XVisualInfo *vis, int attribute,
		 int *value_return)
{
    __GLXvisualConfig *pConfig;
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;
    GLint i;

    /* Initialize the extension, if needed */
    priv = __glXInitialize(dpy);
    if (!priv) {
	/* No extension */
	return GLX_NO_EXTENSION;
    }

    /* Check screen number to see if its valid */
    if ((vis->screen < 0) || (vis->screen >= ScreenCount(dpy))) {
	return GLX_BAD_SCREEN;
    }

    /* Check to see if the GL is supported on this screen */
    psc = &priv->screenConfigs[vis->screen];
    pConfig = psc->configs;
    if (!pConfig) {
	/* No support for GL on this screen regardless of visual */
	if (attribute == GLX_USE_GL) {
	    *value_return = GL_FALSE;
	    return Success;
	}
	return GLX_BAD_VISUAL;
    }

    /* Lookup attribute after first finding a match on the visual */
    for (i = psc->numConfigs; --i >= 0; pConfig++) {
	if (pConfig->vid == vis->visualid) {
	    switch (attribute) {
	      case GLX_USE_GL:
		*value_return = GL_TRUE;
		return Success;
	      case GLX_BUFFER_SIZE:
		*value_return =  pConfig->bufferSize;
		return Success;
	      case GLX_RGBA:
		*value_return = pConfig->rgba;
		return Success;
	      case GLX_RED_SIZE:
		*value_return =  pConfig->redSize;
		return Success;
	      case GLX_GREEN_SIZE:
		*value_return =  pConfig->greenSize;
		return Success;
	      case GLX_BLUE_SIZE:
		*value_return =  pConfig->blueSize;
		return Success;
	      case GLX_ALPHA_SIZE:
		*value_return =  pConfig->alphaSize;
		return Success;
	      case GLX_DOUBLEBUFFER:
		*value_return =  pConfig->doubleBuffer;
		return Success;
	      case GLX_STEREO:
		*value_return =  pConfig->stereo;
		return Success;
	      case GLX_AUX_BUFFERS:
		*value_return =  pConfig->auxBuffers;
		return Success;
	      case GLX_DEPTH_SIZE:
		*value_return =  pConfig->depthSize;
		return Success;
	      case GLX_STENCIL_SIZE:
		*value_return =  pConfig->stencilSize;
		return Success;
	      case GLX_ACCUM_RED_SIZE:
		*value_return =  pConfig->accumRedSize;
		return Success;
	      case GLX_ACCUM_GREEN_SIZE:
		*value_return =  pConfig->accumGreenSize;
		return Success;
	      case GLX_ACCUM_BLUE_SIZE:
		*value_return =  pConfig->accumBlueSize;
		return Success;
	      case GLX_ACCUM_ALPHA_SIZE:
		*value_return =  pConfig->accumAlphaSize;
		return Success;
	      case GLX_LEVEL:
		*value_return =  pConfig->level;
		return Success;
	      case GLX_TRANSPARENT_TYPE_EXT:
		*value_return = pConfig->transparentPixel;
		return Success;
	      case GLX_TRANSPARENT_RED_VALUE_EXT:
		*value_return = pConfig->transparentRed;
		return Success;
	      case GLX_TRANSPARENT_GREEN_VALUE_EXT:
		*value_return = pConfig->transparentGreen;
		return Success;
	      case GLX_TRANSPARENT_BLUE_VALUE_EXT:
		*value_return = pConfig->transparentBlue;
		return Success;
	      case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
		*value_return = pConfig->transparentAlpha;
		return Success;
	      case GLX_TRANSPARENT_INDEX_VALUE_EXT:
		*value_return = pConfig->transparentIndex;
		return Success;
	      case GLX_X_VISUAL_TYPE_EXT:
		switch(pConfig->class) {
		    case TrueColor:    
		      *value_return = GLX_TRUE_COLOR_EXT;   break;
		    case DirectColor:  
		      *value_return = GLX_DIRECT_COLOR_EXT; break;
		    case PseudoColor:  
		      *value_return = GLX_PSEUDO_COLOR_EXT; break;
		    case StaticColor:  
		      *value_return = GLX_STATIC_COLOR_EXT; break;
		    case GrayScale:    
		      *value_return = GLX_GRAY_SCALE_EXT;   break;
		    case StaticGray:   
		      *value_return = GLX_STATIC_GRAY_EXT;  break;
		}
		return Success;
	      case GLX_VISUAL_CAVEAT_EXT:
		*value_return = pConfig->visualRating;
		return Success;
	      default:
		return GLX_BAD_ATTRIBUTE;
	    }
	}
    }

    /*
    ** If we can't find the config for this visual, this visual is not
    ** supported by the OpenGL implementation on the server.
    */
    if (attribute == GLX_USE_GL) {
	*value_return = GL_FALSE;
	return Success;
    }
    return GLX_BAD_VISUAL;
}

/************************************************************************/

/*
** Penalize for more auxiliary buffers than requested
*/
static int AuxScore(int minAux, int aux)
{
    return minAux - aux;
}

/*
** If color is desired, give increasing score for amount available.
** Scale this score by a multiplier to make color differences more
** important than other differences.  Otherwise give decreasing score for
** amount available.
*/
static int ColorScore(int minColor, int color)
{
    if (minColor)
	return 4 * (color - minColor);
    else
	return -color;
}

/*
** If accum buffer is desired, give increasing score for amount
** available.  Otherwise give decreasing score for amount available.
*/
static int AccumScore(int minAccum, int accum)
{
    if (minAccum)
	return accum - minAccum;
    else
	return -accum;
}

/*
** Penalize for indexes larger than requested
*/
static int IndexScore(int minIndex, int ix)
{
    return minIndex - ix;
}

/*
** If depth buffer is desired, give increasing score for amount
** available.  Scale this score by a multiplier to make depth differences
** more important than other non-color differences.  Otherwise give
** decreasing score for amount available.
*/
static int DepthScore(int minDepth, int depth)
{
    if (minDepth)
	return 2 * (depth - minDepth);
    else
	return -depth;
}

/*
** Penalize for stencil buffer larger than requested
*/
static int StencilScore(int minStencil, int stencil)
{
    return minStencil - stencil;
}

/* "Logical" xor - like && or ||; would be ^^ */
#define __GLX_XOR(a,b) (((a) && !(b)) || (!(a) && (b)))

/* Fetch a configuration value */
#define __GLX_GCONF(attrib)				    \
    if (glXGetConfig(dpy, thisVis, attrib, &val)) { 	    \
	XFree((char *)visualList);			    \
	return NULL;					    \
    }


/*
** Return the visual that best matches the template.  Return None if no
** visual matches the template.
*/
XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attribList)
{
    XVisualInfo visualTemplate;
    XVisualInfo *visualList;
    XVisualInfo *thisVis;
    int count, i, maxscore = 0, maxi, score, val, thisVisRating, maxRating = 0;

    /*
    ** Declare and initialize template variables
    */
    int bufferSize = 0;
    int level = 0;
    int rgba = 0;
    int doublebuffer = 0;
    int stereo = 0;
    int auxBuffers = 0;
    int redSize = 0;
    int greenSize = 0;
    int blueSize = 0;
    int alphaSize = 0;
    int depthSize = 0;
    int stencilSize = 0;
    int accumRedSize = 0;
    int accumGreenSize = 0;
    int accumBlueSize = 0;
    int accumAlphaSize = 0;
    /* for visual_info extension */
    int visualType = 0;		
    int visualTypeValue = 0;
    int transparentPixel = 0;
    int transparentPixelValue = GLX_NONE_EXT; 
    int transparentIndex = 0;
    int transparentIndexValue = 0; 
    int transparentRed = 0;	
    int transparentRedValue = 0;
    int transparentGreen = 0;
    int transparentGreenValue = 0; 
    int transparentBlue = 0;
    int transparentBlueValue = 0; 
    int transparentAlpha = 0;	
    int transparentAlphaValue = 0; 
    /* for visual_rating extension */
    int visualRating = 0; 
    int visualRatingValue = GLX_NONE_EXT; 

    /*
    ** Get a list of all visuals, return if list is empty
    */
    visualTemplate.screen = screen;
    visualList = XGetVisualInfo(dpy,VisualScreenMask,&visualTemplate,&count);
    if (visualList == NULL)
	return None;

    /*
    ** Build a template from the defaults and the attribute list
    ** Free visual list and return if an unexpected token is encountered
    */
    while (*attribList != None) {
	switch (*attribList++) {
	  case GLX_USE_GL:
	    break;
	  case GLX_BUFFER_SIZE:
	    bufferSize = *attribList++;
	    break;
	  case GLX_LEVEL:
	    level = *attribList++;
	    break;
	  case GLX_RGBA:
	    rgba = 1;
	    break;
	  case GLX_DOUBLEBUFFER:
	    doublebuffer = 1;
	    break;
	  case GLX_STEREO:
	    stereo = 1;
	    break;
	  case GLX_AUX_BUFFERS:
	    auxBuffers = *attribList++;
	    break;
	  case GLX_RED_SIZE:
	    redSize = *attribList++;
	    break;
	  case GLX_GREEN_SIZE:
	    greenSize = *attribList++;
	    break;
	  case GLX_BLUE_SIZE:
	    blueSize = *attribList++;
	    break;
	  case GLX_ALPHA_SIZE:
	    alphaSize = *attribList++;
	    break;
	  case GLX_DEPTH_SIZE:
	    depthSize = *attribList++;
	    break;
	  case GLX_STENCIL_SIZE:
	    stencilSize = *attribList++;
	    break;
	  case GLX_ACCUM_RED_SIZE:
	    accumRedSize = *attribList++;
	    break;
	  case GLX_ACCUM_GREEN_SIZE:
	    accumGreenSize = *attribList++;
	    break;
	  case GLX_ACCUM_BLUE_SIZE:
	    accumBlueSize = *attribList++;
	    break;
	  case GLX_ACCUM_ALPHA_SIZE:
	    accumAlphaSize = *attribList++;
	    break;
	  case GLX_X_VISUAL_TYPE_EXT:
	    visualType = 1;
	    visualTypeValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_TYPE_EXT:
	    transparentPixel = 1;
	    transparentPixelValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_INDEX_VALUE_EXT:
	    transparentIndex= 1;
	    transparentIndexValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_RED_VALUE_EXT:
	    transparentRed = 1;
	    transparentRedValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_GREEN_VALUE_EXT:
	    transparentGreen = 1;
	    transparentGreenValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_BLUE_VALUE_EXT:
	    transparentBlue = 1;
	    transparentBlueValue = *attribList++;
	    break;
	  case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
	    transparentAlpha = 1;
	    transparentAlphaValue = *attribList++;
	    break;
	  case GLX_VISUAL_CAVEAT_EXT:
	    visualRating = 1;
	    visualRatingValue = *attribList++;
	    break;
	  default:
	    XFree((char *)visualList);
	    return None;
	}
    }

    /*
    ** Eliminate visuals that don't meet minimum requirements
    ** Compute a score for those that do
    ** Remember which visual, if any, got the highest score
    */
    maxi = -1;
    for (i = 0; i < count; i++) {
	score = 0;
	thisVis = &visualList[i];	/* NOTE: used by __GLX_GCONF */

	if (thisVis->class == TrueColor || thisVis->class == PseudoColor) {
	    /* Bump score by one for TrueColor and PseudoColor visuals. */
	    score++;
	}
	
	__GLX_GCONF(GLX_USE_GL);
	if (! val)
	    continue;
	__GLX_GCONF(GLX_LEVEL);
	if (level != val)
	    continue;
	__GLX_GCONF(GLX_RGBA);
	if (__GLX_XOR(rgba, val))
	    continue;
	__GLX_GCONF(GLX_DOUBLEBUFFER);
	if (__GLX_XOR(doublebuffer, val))
	    continue;
	__GLX_GCONF(GLX_STEREO);
	if (__GLX_XOR(stereo, val))
	    continue;
	__GLX_GCONF(GLX_AUX_BUFFERS);
	if (auxBuffers > val)
	    continue;
	else
	    score += AuxScore(auxBuffers, val);
	if (transparentPixel) {
	    if (transparentPixelValue != val)
		continue;
	    if (transparentPixelValue == GLX_TRANSPARENT_TYPE_EXT) {
		if (rgba) {
		    __GLX_GCONF(GLX_TRANSPARENT_RGB_EXT);
		    if (transparentRed) {
			__GLX_GCONF(GLX_TRANSPARENT_RED_VALUE_EXT);
			if (transparentRedValue != val)
			    continue;
		    }
		    if (transparentGreen) {
			__GLX_GCONF(GLX_TRANSPARENT_GREEN_VALUE_EXT);
			if (transparentGreenValue != val)
			    continue;
		    }
		    if (transparentBlue) {
			__GLX_GCONF(GLX_TRANSPARENT_BLUE_VALUE_EXT);
			if (transparentBlueValue != val)
		    continue;
		    }
		    /* Transparent Alpha ignored for now */
		} else {
		    __GLX_GCONF(GLX_TRANSPARENT_INDEX_EXT);
		    if (transparentIndex) {
			__GLX_GCONF(GLX_TRANSPARENT_INDEX_VALUE_EXT);
			if (transparentIndexValue != val)
			    continue;
		    }
		}
	    }
	}
	if (visualType) {
	    __GLX_GCONF(GLX_X_VISUAL_TYPE_EXT);
	    if (visualTypeValue != val)
		continue;
	} else if (rgba) {
	    /* If the extension isn't specified then insure that rgba
	    ** and ci return the usual visual types.
	    */
	    if (!(thisVis->class == TrueColor || thisVis->class == DirectColor))
		continue;
	} else {
	    if (!(thisVis->class == PseudoColor 
			|| thisVis->class == StaticColor))
		continue;
	}
	    
	__GLX_GCONF(GLX_VISUAL_CAVEAT_EXT);
	/** 
	** Unrated visuals are given rating GLX_NONE.
	*/
	thisVisRating = val ? val : GLX_NONE_EXT;
	if (visualRating && (visualRatingValue != val))
	    continue;
	if (rgba) {
	    __GLX_GCONF(GLX_RED_SIZE);
	    if (redSize > val)
		continue;
	    else 
		score += ColorScore(redSize,val);
	    __GLX_GCONF(GLX_GREEN_SIZE);
	    if (greenSize > val)
		continue;
	    else 
		score += ColorScore(greenSize, val);
	    __GLX_GCONF(GLX_BLUE_SIZE);
	    if (blueSize > val)
		continue;
	    else 
		score += ColorScore(blueSize, val);
	    __GLX_GCONF(GLX_ALPHA_SIZE);
	    if (alphaSize > val)
		continue;
	    else 
		score += ColorScore(alphaSize, val);
	    __GLX_GCONF(GLX_ACCUM_RED_SIZE);
	    if (accumRedSize > val)
		continue;
	    else 
		score += AccumScore(accumRedSize, val);
	    __GLX_GCONF(GLX_ACCUM_GREEN_SIZE);
	    if (accumGreenSize > val)
		continue;
	    else 
		score += AccumScore(accumGreenSize, val);
	    __GLX_GCONF(GLX_ACCUM_BLUE_SIZE);
	    if (accumBlueSize > val)
		continue;
	    else 
		score += AccumScore(accumBlueSize, val);
	    __GLX_GCONF(GLX_ACCUM_ALPHA_SIZE);
	    if (accumAlphaSize > val)
		continue;
	    else 
		score += AccumScore(accumAlphaSize, val);
	} else {
	    __GLX_GCONF(GLX_BUFFER_SIZE);
	    if (bufferSize > val)
		continue;
	    else
		score += IndexScore(bufferSize, val);
	}
	__GLX_GCONF(GLX_DEPTH_SIZE);
	if (depthSize > val)
	    continue;
	else
	    score += DepthScore(depthSize, val);
	__GLX_GCONF(GLX_STENCIL_SIZE);
	if (stencilSize > val)
	    continue;
	else
	    score += StencilScore(stencilSize, val);

	/*
	** The visual_rating extension indicates that a NONE visual
	** is always returned in preference to a SLOW one.
	** Note that enum values are in increasing order (NONE < SLOW).
	*/
	if (maxi < 0 || maxRating > thisVisRating) {
	    maxi = i;
	    maxscore = score;
	    maxRating = thisVisRating;
	} else {
	    if (score > maxscore) {
		maxi = i;
		maxscore = score;
	    }
	}
    }

    /*
    ** If no visual is acceptable, return None
    ** Otherwise, create an XVisualInfo list with just the selected X visual
    **   and return this after freeing the original list
    */
    if (maxi < 0) {
	XFree((char *)visualList);
	return None;
    } else {
	visualTemplate.visualid = visualList[maxi].visualid;
	XFree((char *)visualList);
	visualList = XGetVisualInfo(dpy,VisualScreenMask|VisualIDMask,&visualTemplate,&count);
	return visualList;
    }
}

/*
** Query the Server GLX string and cache it in the display private.
** This routine will allocate the necessay space for the string.
*/
static char *QueryServerString( Display *dpy, int opcode,
                                        int screen, int name )
{
    xGLXQueryServerStringReq *req;
    xGLXQueryServerStringReply reply;
    int length, numbytes, slop;
    char *buf;

    /* Send the glXQueryServerString request */
    LockDisplay(dpy);
    GetReq(GLXQueryServerString,req);
    req->reqType = opcode;
    req->glxCode = X_GLXQueryServerString;
    req->screen = screen;
    req->name = name;
    _XReply(dpy, (xReply*) &reply, 0, False);

    length = reply.length;
    numbytes = reply.n;
    slop = numbytes * __GLX_SIZE_INT8 & 3;
    buf = (char *)Xmalloc(numbytes);
    if (!buf) {
        /* Throw data on the floor */
        _XEatData(dpy, length);
    } else {
        _XRead(dpy, (char *)buf, numbytes);
        if (slop) _XEatData(dpy,4-slop);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return buf;
}

#define SEPARATOR " "

static char *combine_strings( const char *cext_string, const char *sext_string )
{
   int clen, slen;
   char *combo_string, *token, *s1;
   const char *s2, *end;

   /*
   ** String can't be longer than min(cstring, sstring)
   ** pull tokens out of shortest string
   ** include space in combo_string for final separator and null terminator
   */
   if ( (clen = strlen( cext_string)) > (slen = strlen( sext_string)) ) {
        combo_string = (char *) Xmalloc( slen + 2 );
	s1 = (char *) malloc( slen + 2 ); strcpy( s1, sext_string );
        s2 = cext_string;
   } else {
        combo_string = (char *) Xmalloc( clen + 2 );
	s1 = (char *) Xmalloc( clen + 2 ); strcpy( s1, cext_string);
        s2 = sext_string;
   }
   if (!combo_string || !s1) {
	if (combo_string) Xfree(combo_string);
	if (s1) Xfree(s1);
        return NULL;
   }
   combo_string[0] = '\0';

   /* Get first extension token */
   token = strtok( s1, SEPARATOR);
   while ( token != NULL ) {

	/*
	** if token in second string then save it
	** beware of extension names which are prefixes of other extension names
	*/
	const char *p = s2;
	end = p + strlen(p);
	while (p < end) {
	    int n = strcspn(p, SEPARATOR);
	    if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) {
		combo_string = strcat( combo_string, token);
		combo_string = strcat( combo_string, SEPARATOR);
	    }
	    p += (n + 1);
	}

        /* Get next extension token */
        token = strtok( NULL, SEPARATOR);
   }
   Xfree(s1);
   return combo_string;
}

const char *glXQueryExtensionsString( Display *dpy, int screen )
{
    __GLXvisualConfig *pConfig;
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;

    /* Initialize the extension, if needed .  This has the added value
       of initializing/allocating the display private */
    priv = __glXInitialize(dpy);
    if (!priv) {
	return NULL;
    }

    /* Check screen number to see if its valid */
    if ((screen < 0) || (screen >= ScreenCount(dpy))) {
	return NULL;
    }

    /* Check to see if the GL is supported on this screen */
    psc = &priv->screenConfigs[screen];
    pConfig = psc->configs;
    if (!pConfig) {
	/* No support for GL on this screen regardless of visual */
	return NULL;
    }
   
    if (!psc->effectiveGLXexts) {
        if (!psc->serverGLXexts) {
	    psc->serverGLXexts = QueryServerString(dpy, priv->majorOpcode,
					  	   screen, GLX_EXTENSIONS);
	}
	psc->effectiveGLXexts = combine_strings(__glXGLXClientExtensions,
						psc->serverGLXexts);
    }

    return psc->effectiveGLXexts;
}

const char *glXGetClientString( Display *dpy, int name )
{
    switch(name) {
	case GLX_VENDOR:
	    return (__glXGLXClientVendorName);
	case GLX_VERSION:
	    return (__glXGLXClientVersion);
	case GLX_EXTENSIONS:
	    return (__glXGLXClientExtensions);
	default:
	    return NULL;
    }
}

const char *glXQueryServerString( Display *dpy, int screen, int name )
{
    __GLXvisualConfig *pConfig;
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;

    /* Initialize the extension, if needed .  This has the added value
       of initializing/allocating the display private */
    priv = __glXInitialize(dpy);
    if (!priv) {
	/* No extension */
	return NULL;
    }

    /* Check screen number to see if its valid */
    if ((screen < 0) || (screen >= ScreenCount(dpy))) {
	return NULL;
    }

    /* Check to see if the GL is supported on this screen */
    psc = &priv->screenConfigs[screen];
    pConfig = psc->configs;
    if (!pConfig) {
	/* No support for GL on this screen regardless of visual */
	return NULL;
    }
 
    switch(name) {
	case GLX_VENDOR:
	    if (!priv->serverGLXvendor) {
	 	priv->serverGLXvendor = 
			QueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_VENDOR);
	    }
	    return(priv->serverGLXvendor);
	case GLX_VERSION:
	    if (!priv->serverGLXversion) {
	 	priv->serverGLXversion = 
			QueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_VERSION);
	    }
	    return(priv->serverGLXversion);
	case GLX_EXTENSIONS:
	    if (!psc->serverGLXexts) {
	 	psc->serverGLXexts = 
			QueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_EXTENSIONS);
	    }
	    return(psc->serverGLXexts);
	default:
	    return NULL;
    }
}

void __glXClientInfo (  Display *dpy, int opcode  )
{
    xGLXClientInfoReq *req;
    int size;

    /* Send the glXClientInfo request */
    LockDisplay(dpy);
    GetReq(GLXClientInfo,req);
    req->reqType = opcode;
    req->glxCode = X_GLXClientInfo;
    req->major = GLX_MAJOR_VERSION;
    req->minor = GLX_MINOR_VERSION;

    size = strlen(__glXGLClientExtensions) + 1;
    req->length += (size + 3) >> 2;
    req->numbytes = size;
    Data(dpy, __glXGLClientExtensions, size);

    UnlockDisplay(dpy);
    SyncHandle();
}

/************************************************************************/
/*
** EXT_import_context entry points
*/
/************************************************************************/

Display *glXGetCurrentDisplay(void)
{
    GLXContext gc = __glXGetCurrentContext();
    if (NULL == gc) return NULL;
    return gc->currentDpy;
}


static int __glXQueryContextInfo(Display *dpy, GLXContext ctx)
{
    xGLXVendorPrivateReq *vpreq;
    xGLXQueryContextInfoEXTReq *req;
    xGLXQueryContextInfoEXTReply reply;
    CARD8 opcode;
    GLuint numValues;

    if (ctx == NULL) {
	return GLX_BAD_CONTEXT;
    }
    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return 0;
    }

    /* Send the glXQueryContextInfoEXT request */
    LockDisplay(dpy);
    GetReqExtra(GLXVendorPrivate,
	sz_xGLXQueryContextInfoEXTReq-sz_xGLXVendorPrivateReq,vpreq);
    req = (xGLXQueryContextInfoEXTReq *)vpreq;
    req->reqType = opcode;
    req->glxCode = X_GLXVendorPrivateWithReply;
    req->vendorCode = X_GLXvop_QueryContextInfoEXT;
    req->context = (unsigned int)(ctx->xid);
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);

    numValues = reply.n;
    if (numValues == 0) return Success;
    if (numValues > __GLX_MAX_CONTEXT_PROPS) return 0;

    {
	int *propList, *pProp;
	int nPropListBytes;
	int i;

	nPropListBytes = numValues << 3;
	propList = (int *) Xmalloc(nPropListBytes);
	if (NULL == propList) {
	    return 0;
	}
	_XRead(dpy, (char *)propList, nPropListBytes);
	pProp = propList;
	for (i=0; i < numValues; i++) {
	    switch (*pProp++) {
	    case GLX_SHARE_CONTEXT_EXT:
		ctx->share_xid = *pProp++;
		break;
	    case GLX_VISUAL_ID_EXT:
		ctx->vid = *pProp++;
		break;
	    case GLX_SCREEN_EXT:
		ctx->screen = *pProp++;
		break;
	    default:
		pProp++;
		continue;
	    }
	}
	Xfree((char *)propList);
    }
    SyncHandle();
    return Success;
}

int glXQueryContextInfoEXT(Display *dpy, GLXContext ctx, 
				int attribute, int *value)
{
    int retVal;

    /* get the information from the server if we don't have it already */
    if (!ctx->isDirect && (ctx->vid == None)) {
	retVal = __glXQueryContextInfo(dpy, ctx);
	if (Success != retVal) return retVal;
    }
    switch (attribute) {
    case GLX_SHARE_CONTEXT_EXT:
	*value = (int)(ctx->share_xid);
	break;
    case GLX_VISUAL_ID_EXT:
	*value = (int)(ctx->vid);
	break;
    case GLX_SCREEN_EXT:
	*value = (int)(ctx->screen);
	break;
    default:
	return GLX_BAD_ATTRIBUTE;
    }
    return Success;
}

GLXContextID glXGetContextIDEXT(const GLXContext ctx)
{
    return ctx->xid;
}

GLXContext glXImportContextEXT(Display *dpy, GLXContextID contextID)
{
    GLXContext ctx;

    if (contextID == None) {
	return NULL;
    }
    if (__glXIsDirect(dpy, contextID)) {
	return NULL;
    }

    ctx = CreateContext(dpy, NULL, NULL, GL_FALSE, contextID);
    if (NULL != ctx) {
	if (Success != __glXQueryContextInfo(dpy, ctx)) {
	   return NULL;
	}
    }
    return ctx;
}

void glXFreeContextEXT(Display *dpy, GLXContext ctx)
{
    DestroyContext(dpy, ctx);
}



/*
 * GLX 1.3 functions - these are just stubs for now!
 */

GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, const int *attribList, int *nitems)
{
    (void) dpy;
    (void) screen;
    (void) attribList;
    (void) nitems;
    return 0;
}


GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)
{
    (void) dpy;
    (void) config;
    (void) renderType;
    (void) shareList;
    (void) direct;
    return 0;
}


GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) attribList;
    return 0;
}


GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) pixmap;
    (void) attribList;
    return 0;
}


GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) win;
    (void) attribList;
    return 0;
}


void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
{
    (void) dpy;
    (void) pbuf;
}


void glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
{
    (void) dpy;
    (void) pixmap;
}


void glXDestroyWindow(Display *dpy, GLXWindow window)
{
    (void) dpy;
    (void) window;
}


GLXDrawable glXGetCurrentReadDrawable(void)
{
    return 0;
}


GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements)
{
   (void) dpy;
   (void) screen;
   (void) nelements;
   return 0;
}


int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config, int attribute, int *value)
{
    (void) dpy;
    (void) config;
    (void) attribute;
    (void) value;
    return 0;
}


void glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask)
{
    (void) dpy;
    (void) drawable;
    (void) mask;
}


XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
{
    (void) dpy;
    (void) config;
    return 0;
}


Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx)
{
    (void) dpy;
    (void) draw;
    (void) read;
    (void) ctx;
    return 0;
}


int glXQueryContext(Display *dpy, GLXContext ctx, int attribute, int *value)
{
    (void) dpy;
    (void) ctx;
    (void) attribute;
    (void) value;
    return 0;
}


void glXQueryDrawable(Display *dpy, GLXDrawable draw, int attribute, unsigned int *value)
{
    (void) dpy;
    (void) draw;
    (void) attribute;
    (void) value;
}


void glXSelectEvent(Display *dpy, GLXDrawable drawable, unsigned long mask)
{
    (void) dpy;
    (void) drawable;
    (void) mask;
}



/*
** Mesa extension stubs.  These will help reduce portability problems.
*/

void glXReleaseBuffersMESA( Display *dpy, GLXDrawable d )
{
   (void) dpy;
   (void) d;
   /* no-op stub */
}


GLXPixmap glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visual,
                                  Pixmap pixmap, Colormap cmap )
{
   (void) dpy;
   (void) visual;
   (void) pixmap;
   (void) cmap;
   return 0;
}


void glXCopySubBufferMESA( Display *dpy, GLXDrawable drawable,
                           int x, int y, int width, int height )
{
   (void) dpy;
   (void) drawable;
   (void) x;
   (void) y;
   (void) width;
   (void) height;
}


GLboolean glXSet3DfxModeMESA( GLint mode )
{
   (void) mode;
   return GL_FALSE;
}


/*
** glXGetProcAddress support
*/

struct name_address_pair {
   const char *Name;
   GLvoid *Address;
};

static struct name_address_pair GLX_functions[] = {
   { "glXChooseVisual", (GLvoid *) glXChooseVisual },
   { "glXCopyContext", (GLvoid *) glXCopyContext },
   { "glXCreateContext", (GLvoid *) glXCreateContext },
   { "glXCreateGLXPixmap", (GLvoid *) glXCreateGLXPixmap },
   { "glXDestroyContext", (GLvoid *) glXDestroyContext },
   { "glXDestroyGLXPixmap", (GLvoid *) glXDestroyGLXPixmap },
   { "glXGetConfig", (GLvoid *) glXGetConfig },
   { "glXGetCurrentContext", (GLvoid *) glXGetCurrentContext },
   { "glXGetCurrentDrawable", (GLvoid *) glXGetCurrentDrawable },
   { "glXIsDirect", (GLvoid *) glXIsDirect },
   { "glXMakeCurrent", (GLvoid *) glXMakeCurrent },
   { "glXQueryExtension", (GLvoid *) glXQueryExtension },
   { "glXQueryVersion", (GLvoid *) glXQueryVersion },
   { "glXSwapBuffers", (GLvoid *) glXSwapBuffers },
   { "glXUseXFont", (GLvoid *) glXUseXFont },
   { "glXWaitGL", (GLvoid *) glXWaitGL },
   { "glXWaitX", (GLvoid *) glXWaitX },

   { "glXGetClientString", (GLvoid *) glXGetClientString },
   { "glXQueryExtensionsString", (GLvoid *) glXQueryExtensionsString },
   { "glXQueryServerString", (GLvoid *) glXQueryServerString },

   { "glXGetCurrentDisplay", (GLvoid *) glXGetCurrentDisplay },

   { "glXChooseFBConfig", (GLvoid *) glXChooseFBConfig },
   { "glXCreateNewContext", (GLvoid *) glXCreateNewContext },
   { "glXCreatePbuffer", (GLvoid *) glXCreatePbuffer },
   { "glXCreatePixmap", (GLvoid *) glXCreatePixmap },
   { "glXCreateWindow", (GLvoid *) glXCreateWindow },
   { "glXDestroyPbuffer", (GLvoid *) glXDestroyPbuffer },
   { "glXDestroyPixmap", (GLvoid *) glXDestroyPixmap },
   { "glXDestroyWindow", (GLvoid *) glXDestroyWindow },
   { "glXGetCurrentReadDrawable", (GLvoid *) glXGetCurrentReadDrawable },
   { "glXGetFBConfigAttrib", (GLvoid *) glXGetFBConfigAttrib },
   { "glXGetFBConfigs", (GLvoid *) glXGetFBConfigs },
   { "glXGetSelectedEvent", (GLvoid *) glXGetSelectedEvent },
   { "glXGetVisualFromFBConfig", (GLvoid *) glXGetVisualFromFBConfig },
   { "glXMakeContextCurrent", (GLvoid *) glXMakeContextCurrent },
   { "glXQueryContext", (GLvoid *) glXQueryContext },
   { "glXQueryDrawable", (GLvoid *) glXQueryDrawable },
   { "glXSelectEvent", (GLvoid *) glXSelectEvent },

   /* extension functions */
   { "glXGetContextIDEXT", (GLvoid *) glXGetContextIDEXT },
   { "glXGetCurrentDrawableEXT", (GLvoid *) glXGetCurrentDrawableEXT },
   { "glXImportContextEXT", (GLvoid *) glXImportContextEXT },
   { "glXFreeContextEXT", (GLvoid *) glXFreeContextEXT },
   { "glXQueryContextInfoEXT", (GLvoid *) glXQueryContextInfoEXT },
   { "glXGetProcAddressARB", (GLvoid *) glXGetProcAddressARB },

   /* Mesa extensions */
   { "glXReleaseBuffersMESA", (GLvoid *) glXReleaseBuffersMESA },
   { "glXCreateGLXPixmapMESA", (GLvoid *) glXCreateGLXPixmapMESA },
   { "glXCopySubBufferMESA", (GLvoid *) glXCopySubBufferMESA },
   { "glXSet3DfxModeMESA", (GLvoid *) glXSet3DfxModeMESA },

   { NULL, NULL }   /* end of list */
};


static const GLvoid *
get_glx_proc_address(const char *funcName)
{
   GLuint i;
   for (i = 0; GLX_functions[i].Name; i++) {
      if (strcmp(GLX_functions[i].Name, funcName) == 0)
         return GLX_functions[i].Address;
   }
   return NULL;
}


void (*glXGetProcAddressARB(const GLubyte *procName))()
{
   typedef void (*gl_function)();
   gl_function f;

#if defined(GLX_DIRECT_RENDERING)
   __glXRegisterExtensions();
#endif

   f = (gl_function) get_glx_proc_address((const char *) procName);
   if (f) {
      return f;
   }

   f = (gl_function) _glapi_get_proc_address((const char *) procName);
   return f;
}
