renderer\qgl.h:
    #include <gl/gl.h>
    #include "glext.h"
    GLExtension_t GLimp_ExtensionPointer( const char *name );

    extensions declarations:
        // ARB_vertex_buffer_object
        extern PFNGLBINDBUFFERARBPROC qglBindBuffer;
        extern PFNGLDELETEBUFFERSARBPROC qglDeleteBuffers;
        ...
        // GL fence sync
        extern PFNGLFENCESYNCPROC				qglFenceSync;
        ...

    // non-windows systems will just redefine qgl* to gl*
    #if defined( ID_GL_HARDLINK )
        #include "qgl_linked.h"
    #else
        // windows systems use a function pointer for each call so we can do our log file intercepts
        extern  void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
        extern  void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
        ...
        #if defined( _WIN32 )
            extern  int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
            extern  int   ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
            ...
        #endif
        #if defined( __linux__ )
            extern XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList );
            extern GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
            ...
        #endif
    #endif


renderer\qgl_linked.h:
    for every GL function:
        #define qglBegin glBegin

    #ifdef GLX_VERSION_1_1 // catch all for any GLX-aware situation
    #define qglXChooseVisual glXChooseVisual
    #define qglXCreateContext glXCreateContext
    #define qglXDestroyContext glXDestroyContext
    #define qglXMakeCurrent glXMakeCurrent
    #define qglXSwapBuffers glXSwapBuffers
    #define qglXGetProcAddressARB glXGetProcAddressARB
    #endif


//===================================================================================


win32\gl_logfuncs.cpp:
    for every GL function:
        static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref) {
        	fprintf( tr.logFile, "glAlphaFunc %s %g\n", EnumString(func), ref );
        	dllAlphaFunc(func, ref);
        }
    linux-only:
        logChooseVisual(Display *dpy, int screen, int *attribList) {...}
        logCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct) {...}
        logDestroyContext(Display *dpy, GLXContext ctx) {...}
        logMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) {...}
        logSwapBuffers(Display *dpy, GLXDrawable drawable) {...}


win32\win_glimp.cpp:
    wgl extensions
    gamma settings
    create window + setup GL on it
    frontend/backend threads
    swap buffers, GLimp_ExtensionPointer

    bool GLimp_Init( glimpParms_t parms ) {
        ...
        driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
    	if ( !QGL_Init( driverName ) ) {
        ...
        GLimp_EnableLogging( ( r_logFile.GetInteger() != 0 ) );
    }
    void GLimp_Shutdown( void ) {
        ...
        QGL_Shutdown();
    }


win32\win_qgl.cpp:
    for every WGL function:
        int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
    for every GL function:
        void ( APIENTRY * qglBegin )(GLenum mode);
        static void ( APIENTRY * dllBegin )(GLenum mode);
    GL enums:
        typedef struct {
        	GLenum	e;
        	const char *name;
        } glEnumName_t;
        #define	DEF(x) { x, #x },
        glEnumName_t	glEnumNames[] = {
            DEF(GL_FALSE)
            DEF(GL_TRUE)
        	{ GL_BYTE, "GL_BYTE" },
        	{ GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
            ...
        static const char *EnumString( GLenum t );
    
    #include "gl_logfuncs.cpp"

    void QGL_Shutdown( void ) {
        //for every GL function:
        qglAccum                     = NULL;
        //for every WGL function:
        qwglCopyContext              = NULL;
    }
    bool QGL_Init( const char *dllname ) {
        ...
        if ( ( win32.hinstOpenGL = LoadLibrary( dllname ) ) == 0 )
        ...
        //for every GL function:
    	qglAccum                     = dllAccum = glAccum;
        //for every WGL function:
        qwglChoosePixelFormat        = ChoosePixelFormat;
    }
    void GLimp_EnableLogging( bool enable ) {
        if ( enable ) {
            ...
        	tr.logFile = fopen( ospath, "wt" );
            ...
            //for every GL function:
           	qglAccum                     = logAccum;
        }
        else {
            //for every GL function:
        	qglAccum                     = dllAccum;
        }

    }


//===================================================================================


linux\glimp.cpp:
    gamma settings
    create window + setup GL on it
    frontend/backend threads
    GLimp_SwapBuffers

    #ifdef ID_GL_HARDLINK
    void GLimp_EnableLogging(bool log) {
    	static bool logging;
    	if (log != logging)
    	{
    		common->DPrintf("GLimp_EnableLogging - disabled at compile time (ID_GL_HARDLINK)\n");
    		logging = log;
    	}
    }
    #endif
    
    void GLimp_Shutdown() {
        ...
        #if !defined( ID_GL_HARDLINK )
    		GLimp_dlclose();
        #endif
        ...
    }
		
    bool GLimp_Init( glimpParms_t a ) {
        ...
        #ifndef ID_GL_HARDLINK
        	if ( !GLimp_dlopen() ) {
        		return false;
        	}
        #endif
        ...
    }


linux\glimp_glenum.h:
    DEF(GL_FALSE)
    DEF(GL_TRUE)
    DEF(GL_BYTE)
    DEF(GL_UNSIGNED_BYTE)
    ...
    DEF(GL_TEXTURE_CUBE_MAP_EXT)
    DEF(GL_TEXTURE_3D)
    DEF(GL_TEXTURE_2D)
    DEF(GL_BLEND)
    ...
    

[generated]\linux\glimp_dlopen.cpp:
    for every GL function:
        void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
        void ( * dllAccum )(GLenum op, GLfloat value);
    for every GLX function (6 items):
        XVisualInfo * ( * qglXChooseVisual )(Display *dpy, int screen, int *attribList);
        XVisualInfo * ( * dllChooseVisual )(Display *dpy, int screen, int *attribList);

    void GLimp_BindNative() {
        //for every GL function:
        qglAccum = dllAccum;
        //for every GLX function:
        qglXChooseVisual = dllChooseVisual;
    }

    bool GLimp_dlopen() {
    	const char *driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "libGL.so.1";
    	if ( !( glHandle = dlopen( driverName, RTLD_NOW | RTLD_GLOBAL ) ) ) {
        ...
        //for every GL function:
        dllAccum = ( void ( APIENTRY *)(GLenum op, GLfloat value) ) dlsym( glHandle, "glAccum" );
        if (!dllAccum) { GLimp_dlsym_failed("glAccum"); return false; }
        //for every GLX function:
        dllChooseVisual = ( XVisualInfo * ( APIENTRY *)(Display *dpy, int screen, int *attribList) ) dlsym( glHandle, "glXChooseVisual" );
        if (!dllChooseVisual) { GLimp_dlsym_failed("glXChooseVisual"); return false; }
        ...
        // make the initial binding
    	GLimp_BindNative();
    }

    void GLimp_dlclose() {
        if (glHandle)
    		dlclose( glHandle );
        ...
        //for every GL function:
        qglAccum = NULL;
        //for every GLX function:
        qglXChooseVisual = NULL;
    }


[generated]\linux\glimp_logfuncs.cpp:
    empty with some ifdefs...


[generated]\linux\glimp_logging.cpp:
    GL enums:
        typedef struct {
        	GLenum	e;
        	const char *name;
        } glEnumName_t;
        #define	DEF(x) { x, #x },
        glEnumName_t	glEnumNames[] = {
            #include "sys/linux/glimp_glenum.h"
        	{ 0, NULL }
        };
        static const char *EnumString( GLenum t )
    
    #include "glimp_logfuncs.cpp"

    void GLimp_BindLogging() {/*empty*/}
    
    void GLimp_EnableLogging(bool enable) {
        ...
        if ( enable ) {
            ...
    		tr.logFile = fopen( ospath, "wt" );
        	GLimp_BindLogging();
    	} else {
    		GLimp_BindNative();
    	}
    }


[generated]\linux\glimp_stub.cpp:
    //for every GL function:
        void glAccum(GLenum op, GLfloat value){}
    //for every GLX function:
        XVisualInfo * glXChooseVisual(Display *dpy, int screen, int *attribList){}

    GLenum glGetError(void){return 0;}
    GLuint glGenLists(GLsizei range){return 0;}
    void glGetIntegerv(GLenum pname, GLint *params){ ... }

    const GLubyte * glGetString(GLenum name){
	    switch( name ) {
    		case GL_EXTENSIONS: return (GLubyte *)"GL_ARB_multitexture GL_ARB_texture_env_combine GL_ARB_texture_cube_map GL_ARB_texture_env_dot3";
    	}
    	return (const GLubyte *)"";
    }


[generated]\gllog\gl_extensions.cpp:
    GLExtension_t GLimp_ExtensionPointer( const char *name ) {
        if ( strstr( name, "wgl" ) == name ) {
    		common->DPrintf( "WARNING: GLimp_ExtensionPointer for '%s'\n", name );
    	}
        #ifdef ID_DEDICATED
        	common->Printf("GLimp_ExtensionPointer %s\n", name);
        	return StubFunction;
        #else
            ...
            ret = qglXGetProcAddressARB((const GLubyte *) name);
            return res;
            ...
        #endif
    }
