Commits

Jason McKesson committed b9f8c5b

New version of the GL loader that also works in Linux.

Comments (0)

Files changed (81)

glload/Test/Test4.lua

+
+project "Test"
+	kind "WindowedApp"
+	language "c++"
+	includedirs { "../include" }
+	links {"glload"}
+
+	configuration "windows"
+		flags { "WinMain" }
+		defines {"WIN32"}
+		files { "windows.cpp", }
+		links { "OpenGL32" }
+
+	configuration "linux"
+		files { "linux.cpp", }
+		links { "GL" }
+	
+	configuration "Debug"
+		flags "Unicode";
+		defines {"DEBUG", "_DEBUG", "MEMORY_DEBUGGING"};
+		objdir "Debug";
+		flags "Symbols";
+	
+	configuration "Release"
+		defines {"NDEBUG", "RELEASE"};
+		flags "Unicode";
+		flags {"OptimizeSpeed", "NoFramePointer", "ExtraWarnings", "NoEditAndContinue"};
+		objdir "Release";
+

glload/Test/linux.cpp

+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "glload/gl_2_1.h"
+#include "glload/glx_exts.h"
+#include "glload/gll.h"
+ 
+// Helper to check for extension string presence.  Adapted from:
+//   http://www.opengl.org/resources/features/OGLextensions/
+static bool isExtensionSupported(const char *extList, const char *extension)
+{
+  const char *start;
+  const char *where, *terminator;
+ 
+  /* Extension names should not have spaces. */
+  where = strchr(extension, ' ');
+  if ( where || *extension == '\0' )
+    return false;
+ 
+  /* It takes a bit of care to be fool-proof about parsing the
+     OpenGL extensions string. Don't be fooled by sub-strings,
+     etc. */
+  for ( start = extList; ; ) {
+    where = strstr( start, extension );
+ 
+    if ( !where )
+      break;
+ 
+    terminator = where + strlen( extension );
+ 
+    if ( where == start || *(where - 1) == ' ' )
+      if ( *terminator == ' ' || *terminator == '\0' )
+        return true;
+ 
+    start = terminator;
+  }
+ 
+  return false;
+}
+
+static bool ctxErrorOccurred = false;
+static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
+{
+    ctxErrorOccurred = true;
+    return 0;
+}
+ 
+int main (int argc, char ** argv)
+{
+  Display *display = XOpenDisplay(0);
+ 
+  if ( !display )
+  {
+    printf( "Failed to open X display\n" );
+    exit(1);
+  }
+ 
+  // Get a matching FB config
+  static int visual_attribs[] =
+    {
+      GLX_X_RENDERABLE    , True,
+      GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
+      GLX_RENDER_TYPE     , GLX_RGBA_BIT,
+      GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,
+      GLX_RED_SIZE        , 8,
+      GLX_GREEN_SIZE      , 8,
+      GLX_BLUE_SIZE       , 8,
+      GLX_ALPHA_SIZE      , 8,
+      GLX_DEPTH_SIZE      , 24,
+      GLX_STENCIL_SIZE    , 8,
+      GLX_DOUBLEBUFFER    , True,
+      //GLX_SAMPLE_BUFFERS  , 1,
+      //GLX_SAMPLES         , 4,
+      None
+    };
+ 
+  int glx_major, glx_minor;
+ 
+  // FBConfigs were added in GLX version 1.3.
+  if ( !glXQueryVersion( display, &glx_major, &glx_minor ) || 
+       ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
+  {
+    printf( "Invalid GLX version" );
+    exit(1);
+  }
+ 
+  printf( "Getting matching framebuffer configs\n" );
+  int fbcount;
+  GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ), 
+                                        visual_attribs, &fbcount );
+  if ( !fbc )
+  {
+    printf( "Failed to retrieve a framebuffer config\n" );
+    exit(1);
+  }
+  printf( "Found %d matching FB configs.\n", fbcount );
+ 
+  // Pick the FB config/visual with the most samples per pixel
+  printf( "Getting XVisualInfos\n" );
+  int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
+ 
+  int i;
+  for ( i = 0; i < fbcount; i++ )
+  {
+    XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
+    if ( vi )
+    {
+      int samp_buf, samples;
+      glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
+      glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES       , &samples  );
+ 
+      printf( "  Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
+              " SAMPLES = %d\n", 
+              i, (unsigned int)vi->visualid, samp_buf, samples );
+ 
+      if ( best_fbc < 0 || samp_buf && samples > best_num_samp )
+        best_fbc = i, best_num_samp = samples;
+      if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp )
+        worst_fbc = i, worst_num_samp = samples;
+    }
+    XFree( vi );
+  }
+ 
+  GLXFBConfig bestFbc = fbc[ best_fbc ];
+ 
+  // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
+  XFree( fbc );
+ 
+  // Get a visual
+  XVisualInfo *vi = glXGetVisualFromFBConfig( display, bestFbc );
+  printf( "Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid );
+ 
+  printf( "Creating colormap\n" );
+  XSetWindowAttributes swa;
+  Colormap cmap;
+  swa.colormap = cmap = XCreateColormap( display,
+                                         RootWindow( display, vi->screen ), 
+                                         vi->visual, AllocNone );
+  swa.background_pixmap = None ;
+  swa.border_pixel      = 0;
+  swa.event_mask        = StructureNotifyMask;
+ 
+  printf( "Creating window\n" );
+  Window win = XCreateWindow( display, RootWindow( display, vi->screen ), 
+                              0, 0, 100, 100, 0, vi->depth, InputOutput, 
+                              vi->visual, 
+                              CWBorderPixel|CWColormap|CWEventMask, &swa );
+  if ( !win )
+  {
+    printf( "Failed to create window.\n" );
+    exit(1);
+  }
+ 
+  // Done with the visual info data
+  XFree( vi );
+ 
+  XStoreName( display, win, "GL 3.0 Window" );
+ 
+  printf( "Mapping window\n" );
+  XMapWindow( display, win );
+ 
+  // Get the default screen's GLX extension list
+  const char *glxExts = glXQueryExtensionsString( display,
+                                                  DefaultScreen( display ) );
+ 
+  // NOTE: It is not necessary to create or make current to a context before
+  // calling glXGetProcAddressARB
+  glload::LoadGLXFunctions(display, DefaultScreen( display ));
+  /**
+  glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
+  glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
+           glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
+      **/
+ 
+  GLXContext ctx = 0;
+ 
+  // Install an X error handler so the application won't exit if GL 3.0
+  // context allocation fails.
+  //
+  // Note this error handler is global.  All display connections in all threads
+  // of a process use the same error handler, so be sure to guard against other
+  // threads issuing X commands while this code is running.
+  ctxErrorOccurred = false;
+  int (*oldHandler)(Display*, XErrorEvent*) =
+      XSetErrorHandler(&ctxErrorHandler);
+ 
+  // Check for the GLX_ARB_create_context extension string and the function.
+  // If either is not present, use GLX 1.3 context creation method.
+  if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) ||
+       !glXCreateContextAttribsARB )
+  {
+    printf( "glXCreateContextAttribsARB() not found"
+            " ... using old-style GLX context\n" );
+    ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
+  }
+ 
+  // If it does, try to get a GL 3.0 context!
+  else
+  {
+    int context_attribs[] =
+      {
+        GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+        GLX_CONTEXT_MINOR_VERSION_ARB, 3,
+        //GLX_CONTEXT_FLAGS_ARB        , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+        None
+      };
+ 
+    printf( "Creating context\n" );
+    ctx = glXCreateContextAttribsARB( display, bestFbc, 0,
+                                      True, context_attribs );
+ 
+    // Sync to ensure any errors generated are processed.
+    XSync( display, False );
+    if ( !ctxErrorOccurred && ctx )
+      printf( "Created GL 3.0 context\n" );
+    else
+    {
+      // Couldn't create GL 3.0 context.  Fall back to old-style 2.x context.
+      // When a context version below 3.0 is requested, implementations will
+      // return the newest context version compatible with OpenGL versions less
+      // than version 3.0.
+      // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
+      context_attribs[1] = 1;
+      // GLX_CONTEXT_MINOR_VERSION_ARB = 0
+      context_attribs[3] = 0;
+ 
+      ctxErrorOccurred = false;
+ 
+      printf( "Failed to create GL 3.0 context"
+              " ... using old-style GLX context\n" );
+      ctx = glXCreateContextAttribsARB( display, bestFbc, 0, 
+                                        True, context_attribs );
+    }
+  }
+ 
+  // Sync to ensure any errors generated are processed.
+  XSync( display, False );
+ 
+  // Restore the original error handler
+  XSetErrorHandler( oldHandler );
+ 
+  if ( ctxErrorOccurred || !ctx )
+  {
+    printf( "Failed to create an OpenGL context\n" );
+    exit(1);
+  }
+ 
+  // Verifying that context is a direct context
+  if ( ! glXIsDirect ( display, ctx ) )
+  {
+    printf( "Indirect GLX rendering context obtained\n" );
+  }
+  else
+  {
+    printf( "Direct GLX rendering context obtained\n" );
+  }
+ 
+  printf( "Making context current\n" );
+  glXMakeCurrent( display, win, ctx );
+  
+  glload::LoadFunctions();
+ 
+  glClearColor ( 0, 0.5, 1, 1 );
+  glClear ( GL_COLOR_BUFFER_BIT );
+  glXSwapBuffers ( display, win );
+  
+  printf("Vendor: %s\n", glGetString(GL_VENDOR));
+  printf("Renderer: %s\n", glGetString(GL_RENDERER));
+  printf("Version: %s\n", glGetString(GL_VERSION));
+ 
+  sleep( 1 );
+ 
+  glClearColor ( 1, 0.5, 0, 1 );
+  glClear ( GL_COLOR_BUFFER_BIT );
+  glXSwapBuffers ( display, win );
+ 
+  sleep( 1 );
+ 
+  glXMakeCurrent( display, 0, 0 );
+  glXDestroyContext( display, ctx );
+ 
+  XDestroyWindow( display, win );
+  XFreeColormap( display, cmap );
+  XCloseDisplay( display );
+}

glload/Test/windows.cpp

+/*
+*		This Code Was Created By Jeff Molofee 2000
+*		A HUGE Thanks To Fredric Echols For Cleaning Up
+*		And Optimizing This Code, Making It More Flexible!
+*		If You've Found This Code Useful, Please Let Me Know.
+*		Visit My Site At nehe.gamedev.net
+*/
+
+#include <windows.h>		// Header File For Windows
+#include <tchar.h>
+#include "glload\gl_2_1.h"
+#include "glload\wgl_exts.h"
+#include <gl\glu.h>			// Header File For The GLu32 Library
+//#include <gl\glaux.h>		// Header File For The Glaux Library
+#include "glload\gll.h"
+
+HDC			hDC=NULL;		// Private GDI Device Context
+HGLRC		hRC=NULL;		// Permanent Rendering Context
+HWND		hWnd=NULL;		// Holds Our Window Handle
+HINSTANCE	hInstance;		// Holds The Instance Of The Application
+
+bool	keys[256];			// Array Used For The Keyboard Routine
+bool	active=TRUE;		// Window Active Flag Set To TRUE By Default
+bool	fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default
+
+LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc
+
+GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
+{
+	if (height==0)										// Prevent A Divide By Zero By
+	{
+		height=1;										// Making Height Equal One
+	}
+
+	glViewport(width / 4, height / 4, width / 2, height / 2);						// Reset The Current Viewport
+
+	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
+	glLoadIdentity();									// Reset The Projection Matrix
+
+	//Give me an orthographic projection.
+	glOrtho(-1, 1, -1, 1, -1, 1);
+
+	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
+	glLoadIdentity();									// Reset The Modelview Matrix
+}
+
+int InitGL(GLvoid)										// All Setup For OpenGL Goes Here
+{
+	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
+	glClearColor(1.0f, 1.0f, 1.0f, 0.5f);				// White Background
+	glClearDepth(1.0f);									// Depth Buffer Setup
+	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
+	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
+	return TRUE;										// Initialization Went OK
+}
+
+int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
+{
+	static bool bFirstTime = true;
+	static GLuint bufferName = 0;
+
+	if(bFirstTime)
+	{
+		bFirstTime = false;
+
+		glGenBuffers(1, &bufferName);
+
+		static int iVal1 = wglext_ARB_multisample;
+
+		iVal1++;
+	}
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
+	glLoadIdentity();									// Reset The Current Modelview Matrix
+
+	glDepthRange(0.0f, 0.5f);
+	glBegin(GL_QUADS);
+	{
+		//Define the color (blue)
+		glColor3ub(0, 0, 255);
+
+		//Draw our four points, clockwise.
+		glVertex3f(-0.5, 0.5, 0);
+		glVertex3f(0.5, 0.5, 0);
+		glVertex3f(0.5, -0.5, 0);
+		glVertex3f(-0.5, -0.5, 0);
+
+	}
+	glEnd();
+
+	glDepthRange(0.5f, 1.0f);
+	glBegin(GL_QUADS);
+	{
+		//Gray square.
+		glColor3ub(128, 128, 128);
+
+		//Draw our four points, clockwise.
+		glVertex3f(-1, 1, -0.5);
+		glVertex3f(1, 1, -0.5);
+		glVertex3f(1, -1, 0.5);
+		glVertex3f(-1, -1, 0.5);
+	}
+	glEnd();
+
+
+	return TRUE;										// Everything Went OK
+}
+
+GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
+{
+	if (fullscreen)										// Are We In Fullscreen Mode?
+	{
+		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
+		ShowCursor(TRUE);								// Show Mouse Pointer
+	}
+
+	if (hRC)											// Do We Have A Rendering Context?
+	{
+		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
+		{
+			MessageBox(NULL,_T("Release Of DC And RC Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		}
+
+		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
+		{
+			MessageBox(NULL,_T("Release Rendering Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		}
+		hRC=NULL;										// Set RC To NULL
+	}
+
+	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
+	{
+		MessageBox(NULL,_T("Release Device Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hDC=NULL;										// Set DC To NULL
+	}
+
+	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
+	{
+		MessageBox(NULL,_T("Could Not Release hWnd."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hWnd=NULL;										// Set hWnd To NULL
+	}
+
+	if (!UnregisterClass(_T("OpenGL"),hInstance))			// Are We Able To Unregister Class
+	{
+		MessageBox(NULL,_T("Could Not Unregister Class."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hInstance=NULL;									// Set hInstance To NULL
+	}
+}
+
+/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
+*	title			- Title To Appear At The Top Of The Window				*
+*	width			- Width Of The GL Window Or Fullscreen Mode				*
+*	height			- Height Of The GL Window Or Fullscreen Mode			*
+*	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
+*	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
+
+BOOL CreateGLWindow(TCHAR* title, int width, int height, int bits, bool fullscreenflag)
+{
+	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
+	WNDCLASS	wc;						// Windows Class Structure
+	DWORD		dwExStyle;				// Window Extended Style
+	DWORD		dwStyle;				// Window Style
+	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
+	WindowRect.left=(long)0;			// Set Left Value To 0
+	WindowRect.right=(long)width;		// Set Right Value To Requested Width
+	WindowRect.top=(long)0;				// Set Top Value To 0
+	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height
+
+	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag
+
+	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
+	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
+	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
+	wc.cbClsExtra		= 0;									// No Extra Window Data
+	wc.cbWndExtra		= 0;									// No Extra Window Data
+	wc.hInstance		= hInstance;							// Set The Instance
+	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
+	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
+	wc.hbrBackground	= NULL;									// No Background Required For GL
+	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
+	wc.lpszClassName	= _T("OpenGL");								// Set The Class Name
+
+	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
+	{
+		MessageBox(NULL,_T("Failed To Register The Window Class."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;											// Return FALSE
+	}
+
+	if (fullscreen)												// Attempt Fullscreen Mode?
+	{
+		DEVMODE dmScreenSettings;								// Device Mode
+		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
+		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
+		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
+		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
+		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
+		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+
+		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
+		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+		{
+			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
+			if (MessageBox(NULL,
+				_T("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),
+				_T("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
+			{
+				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE
+			}
+			else
+			{
+				// Pop Up A Message Box Letting User Know The Program Is Closing.
+				MessageBox(NULL,_T("Program Will Now Close."),_T("ERROR"),MB_OK|MB_ICONSTOP);
+				return FALSE;									// Return FALSE
+			}
+		}
+	}
+
+	if (fullscreen)												// Are We Still In Fullscreen Mode?
+	{
+		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
+		dwStyle=WS_POPUP;										// Windows Style
+		ShowCursor(FALSE);										// Hide Mouse Pointer
+	}
+	else
+	{
+		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
+		dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style
+	}
+
+	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size
+
+	int iScreenWidth = 1280;
+	int iScreenHeight = 720;
+
+	int iWindowPosX = iScreenWidth - (WindowRect.right-WindowRect.left);
+	int iWindowPosY = iScreenHeight - (WindowRect.bottom-WindowRect.top);
+	iWindowPosY -= 100; //Keep it off the bottom.
+
+	// Create The Window
+	if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
+		_T("OpenGL"),						// Class Name
+		title,								// Window Title
+		dwStyle |							// Defined Window Style
+		WS_CLIPSIBLINGS |					// Required Window Style
+		WS_CLIPCHILDREN,					// Required Window Style
+		iWindowPosX, iWindowPosY,								// Window Position
+		WindowRect.right-WindowRect.left,	// Calculate Window Width
+		WindowRect.bottom-WindowRect.top,	// Calculate Window Height
+		NULL,								// No Parent Window
+		NULL,								// No Menu
+		hInstance,							// Instance
+		NULL)))								// Dont Pass Anything To WM_CREATE
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Window Creation Error."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
+	{
+		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
+			1,											// Version Number
+			PFD_DRAW_TO_WINDOW |						// Format Must Support Window
+			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
+			PFD_DOUBLEBUFFER,							// Must Support Double Buffering
+			PFD_TYPE_RGBA,								// Request An RGBA Format
+			bits,										// Select Our Color Depth
+			0, 0, 0, 0, 0, 0,							// Color Bits Ignored
+			0,											// No Alpha Buffer
+			0,											// Shift Bit Ignored
+			0,											// No Accumulation Buffer
+			0, 0, 0, 0,									// Accumulation Bits Ignored
+			16,											// 16Bit Z-Buffer (Depth Buffer)  
+			0,											// No Stencil Buffer
+			0,											// No Auxiliary Buffer
+			PFD_MAIN_PLANE,								// Main Drawing Layer
+			0,											// Reserved
+			0, 0, 0										// Layer Masks Ignored
+	};
+
+	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Create A GL Device Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Find A Suitable PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Set The PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Create A GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Activate The GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	glload::LoadWinFunctions(hDC);
+	glload::LoadFunctions();
+
+	ShowWindow(hWnd,SW_SHOW);						// Show The Window
+	SetForegroundWindow(hWnd);						// Slightly Higher Priority
+	SetFocus(hWnd);									// Sets Keyboard Focus To The Window
+	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen
+
+	if (!InitGL())									// Initialize Our Newly Created GL Window
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Initialization Failed."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	return TRUE;									// Success
+}
+
+LRESULT CALLBACK WndProc(	HWND	hWnd,			// Handle For This Window
+						 UINT	uMsg,			// Message For This Window
+						 WPARAM	wParam,			// Additional Message Information
+						 LPARAM	lParam)			// Additional Message Information
+{
+	switch (uMsg)									// Check For Windows Messages
+	{
+	case WM_ACTIVATE:							// Watch For Window Activate Message
+		{
+			if (!HIWORD(wParam))					// Check Minimization State
+			{
+				active=TRUE;						// Program Is Active
+			}
+			else
+			{
+				active=FALSE;						// Program Is No Longer Active
+			}
+
+			return 0;								// Return To The Message Loop
+		}
+
+	case WM_SYSCOMMAND:							// Intercept System Commands
+		{
+			switch (wParam)							// Check System Calls
+			{
+			case SC_SCREENSAVE:					// Screensaver Trying To Start?
+			case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
+				return 0;							// Prevent From Happening
+			}
+			break;									// Exit
+		}
+
+	case WM_CLOSE:								// Did We Receive A Close Message?
+		{
+			PostQuitMessage(0);						// Send A Quit Message
+			return 0;								// Jump Back
+		}
+
+	case WM_KEYDOWN:							// Is A Key Being Held Down?
+		{
+			keys[wParam] = TRUE;					// If So, Mark It As TRUE
+			return 0;								// Jump Back
+		}
+
+	case WM_KEYUP:								// Has A Key Been Released?
+		{
+			keys[wParam] = FALSE;					// If So, Mark It As FALSE
+			return 0;								// Jump Back
+		}
+
+	case WM_SIZE:								// Resize The OpenGL Window
+		{
+			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height
+			return 0;								// Jump Back
+		}
+	}
+
+	// Pass All Unhandled Messages To DefWindowProc
+	return DefWindowProc(hWnd,uMsg,wParam,lParam);
+}
+
+int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
+				   HINSTANCE	hPrevInstance,		// Previous Instance
+				   LPSTR		lpCmdLine,			// Command Line Parameters
+				   int			nCmdShow)			// Window Show State
+{
+	MSG		msg;									// Windows Message Structure
+	BOOL	done=FALSE;								// Bool Variable To Exit Loop
+
+	// Ask The User Which Screen Mode They Prefer
+	//	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
+	{
+		fullscreen=FALSE;							// Windowed Mode
+	}
+
+	// Create Our OpenGL Window
+	if (!CreateGLWindow(_T("NeHe's OpenGL Framework"),640,480,32,fullscreen))
+	{
+		return 0;									// Quit If Window Was Not Created
+	}
+
+	while(!done)									// Loop That Runs While done=FALSE
+	{
+		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
+		{
+			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
+			{
+				done=TRUE;							// If So done=TRUE
+			}
+			else									// If Not, Deal With Window Messages
+			{
+				TranslateMessage(&msg);				// Translate The Message
+				DispatchMessage(&msg);				// Dispatch The Message
+			}
+		}
+		else										// If There Are No Messages
+		{
+			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
+			if (active)								// Program Active?
+			{
+				if (keys[VK_ESCAPE])				// Was ESC Pressed?
+				{
+					done=TRUE;						// ESC Signalled A Quit
+				}
+				else								// Not Time To Quit, Update Screen
+				{
+					DrawGLScene();					// Draw The Scene
+					SwapBuffers(hDC);				// Swap Buffers (Double Buffering)
+				}
+			}
+
+			if (keys[VK_F1])						// Is F1 Being Pressed?
+			{
+				keys[VK_F1]=FALSE;					// If So Make Key FALSE
+				KillGLWindow();						// Kill Our Current Window
+
+				// Recreate Our OpenGL Window
+				if (!CreateGLWindow(_T("NeHe's OpenGL Framework"),640,480,32,fullscreen))
+				{
+					return 0;						// Quit If Window Was Not Created
+				}
+			}
+		}
+	}
+
+	// Shutdown
+	KillGLWindow();									// Kill The Window
+	return ((int)msg.wParam);							// Exit The Program
+}

glload/codegen/ConvertAllSpecFilesToLua.lua

+--[[
+Running this file will convert all of the current spec files into lua files.
+
+The lua files can have dofile run on them; this will return a table as formatted in
+ExtractSpecsToFile.lua.
+]]
+
+require "_ExtractSpecsToFile"
+
+ExtractSpecsToFile("glspec.lua", {
+	glspec = "gl.spec",
+	enumext = "enumext.spec",
+	gltm = "gl.tm"
+	})
+
+ExtractSpecsToFile("wglspec.lua", {
+	glspec = "wglext.spec",
+	enumext = "wglenumext.spec",
+	gltm = "wgl.tm"
+	},
+	"WGL")
+
+ExtractSpecsToFile("glxspec.lua", {
+	glspec = "glxext.spec",
+	enumext = "glxenumext.spec",
+	gltm = "glx.tm"
+	})
+

glload/codegen/How it works.txt

+== File sturcture ==
+
+The Lua scripts here use standard Lua API calls and no external modules.
+
+All Lua files that start with an "_" are library files. They usually add at least one global function, usually named the same as the filename (sans "_"). Some are just a collection of miscellaneous functions that do certain things.
+
+Lua files that don't start with the underscore are to be executed on the command line. They may take parameters.
+
+== The generation process ==
+
+The code-generation process is 2-stage. The first stage is the conversion of the .spec and .tm files into a .lua file that returns a giant table containing all of this information. The .lua files responsible for this conversion are:
+
+* ConvertAllSpecFilesToLua.lua: Causes generation of all .lua spec files. It doesn't take parameters.
+** _ExtractSpecsToFile.lua: Generates a single .lua spec file.
+*** _ExtractEnums.lua: Processes enumext.spec to retrieve the enums.
+*** _ExtractExts.lua: Processes enumext.spec to retrieve the extension list.
+*** _ExtractTypes.lua: Processes gl.tm to retrieve the typemap data.
+*** _ExtractFuncs.lua: Processes gl.spec to retrieve the function data.
+*** _TableWriter.lua: Writes a table as a Lua-compileable file. Think LSON.
+
+The second stage uses the .lua file to generate the code. The output from this stage is described above. The files involved are:
+
+* makeAllFiles.lua: Causes the generation of all code-gen files. It doesn't take parameters.
+** LoadLuaSpec.lua: Loads the spec we created above. However, it does some pre-processing to make the code-generation easier (tables indexed by enum and so forth). It also performs some data fixup that removes some... annoying things that the spec files leave in.
+** MakeExtHeaderFile.lua: Generates a header file for a particular OpenGL version. This is used by external code to use OpenGL.
+** MakeMainHeaderFile.lua: Generates an internal header that is used to load extension function pointers.
+** MakeMainSourceFile.lua: Generates an internal source file that does the loading of the extension function pointers.
+** MakeCoreHeaderFile.lua: Generates an internal header file that contains a struct defining all of the internal function pointers.
+** MakeCoreSourceFile.lua: Generates an internal source file that will fill this struct with function pointers from the standard gl.h.
+
+== The gl.h issue ==
+
+Different versions of OpenGL libraries have different base implementations. On Windows, 1.1 is the base, so all of those functions are statically defined. On other platforms, there will be different levels of GL.
+
+What we will do is have a source file that includes the standard gl.h. It has a function that copies all the 1.1 function pointers into a prepared struct. Then, if a core function fails to get a function pointer, it can try to get it from the prepared struct. The struct is there to keep down name polution.
+
+In order to make this work, core functions ''must'' be #defined with their name, rather than defined as variables. If you don't do this, you get linker errors (multiple definition). Thus, all core OpenGL functions (including core extensions) must #define the name as a variable, with the variable name being externed instead. The variable name will be of the form "__gle*", where "*" is the rest of the function name.
+
+== The generated files ==
+
+The code-generation process will generate a number of files. The types of these files is as follows.
+
+* ''External headers:'' These are the header files that the user #includes into their project. They define OpenGL entrypoints and enums for a particular OpenGL version/profile pair.
+
+* ''Main internal header:'' This header exposes the extension function loading functions to the non-code-generated GLE runtime.
+
+* ''Main source file:'' This implements the functions exposed by the Main internal header.
+
+* ''Core internal header:'' This header exposes a struct containing all of the core entrypoints. It also has a function to load standard core function pointers from this.
+
+* ''Core source header:'' Implements the functions from the Core internal header.
+
+=== External headers ===
+
+The standard generation process will create headers for the following combination of GL versions and profiles:
+
+* GL 2.1
+* GL 3.0
+* GL 3.1 core
+* GL 3.1 compatibility
+* GL 3.2 core
+* GL 3.2 compatibility
+* etc.
+
+The external code simply includes one of these header files. That will get them access to what they need.
+
+These files will have the following in them:
+
+* Core and extension #defines, as appropriate to the version.
+* Core and extension entrypoints, as appropriate to the version.
+* For each extension, a variable extern; if the variable is GL_FALSE, then the extension is not defined.
+
+=== Main internal header ===
+
+There will be a single internal header to the main loading functions. This file contains the following declarations:
+
+* A mapping table. An array of map objects, where the map object contains a string extension name, an integer pointer to the "is extension loaded" variable for that extension, and a function pointer to a loader for that extension (NULL if has no functions).
+* The size of the mapping table.
+* A function to clear all of the extension variables.
+* For each of the possible version/profile combinations, a function that loads the core entrypoints, including core extensions appropriate to the verison/profile (but not including regular extensions). Returns 1 if the function pointers could be loaded, and 0 otherwise. Will set the extension variables for any core extensions it loads.
+* A function to load the "base" entrypoints. See below.
+* The "base" entrypoint declarations, as well as "base" enum defines.
+
+All internal functions have the prefix "gleInt_".
+
+==== Base declarations ====
+
+The "base" declarations are those that the basic system needs to function. These are:
+
+* ''glGetString'': Used to get the version number and extensions, possibly.
+* ''glGetStringi'': Used to get the extensions in 3.x versions. Can be NULL.
+* ''glGetIntegerv'': Used to get the number of extensions in 3.x versions.
+* ''GL_VERSION'': Enum needed to version numbers.
+* ''GL_EXTENSIONS'': Enum needed to get extensions.
+* ''GL_NUM_EXTENSIONS'': Enum used to get the number of extensions.
+* ''GL_CONTEXT_PROFILE_MASK'': Enum used to test the profile type.
+* ''GL_CONTEXT_CORE_PROFILE_BIT'': Enum for the core profile.
+* ''GL_CONTEXT_COMPATIBILITY_PROFILE_BIT'': Enum for the compatibility profile.
+* ''GL_TRUE'' and ''GL_FALSE'': so that we can use them.
+
+=== Core internal header ===
+
+This header file exposes a struct (with an expected name) that stores function pointers for ''all'' core functions. It also exposes a single function that will clear this struct, then load the standard function pointers into it.
+
+=== Core source file ===
+
+This file the standard #includes "gl/gl.h". It also implements the function above.
+
+The first phase of the function will clear the struct. The second phase is platform-specific. Each platform in the code generator will have a define to #ifdef around, and it will also specify which core versions need to be looked at.
+
+Note: the struct in question may require some defines for the functions to be placed in the source file.
+
+=== Main source file ===
+
+This file does the following:
+
+* Define all of the externed extension variables.
+* Define all of the externed function pointers.
+* Initialize the mapping table from extension name to extension variable.
+* Implement the function that clears extension variables.
+* For each extension with function pointers, implement a ''static'' function to load the function pointers for it.
+* For each of the version/profile pairs, implement a function that loads the core function pointers for that version/profile pair. This includes core extensions, but only those appropriate to the verison. If a core function pointer is not found, then check the core internal struct for one.
+* Implement the function that loads the "base" stuff.
+
+==== Extension loading ====
+
+The functions that load extensions will return 0 if some of the function pointers were not there, and 1 otherwise. Unfortunately, to see if a function pointer is there, it must be tested against the values -1, 0, 1, 2, and 3.
+
+==== Core loading ====
+
+The first thing any of these functions will do is clear the Core Function struct.
+
+The function that loads core entrypoints will also load entrypoints for appropriate core extensions. If a core extension loads successfully, its extension variable will be set.
+
+If a core function pointer is not available, check the struct of core functions from the Core header. If it's in there, then use that. Otherwise, fail and return 0.
+
+Loading a core extension is slightly different from loading a regular extension in this respect. If a core extension is being loaded as a core extension, then it should be loaded as a core extension, which requires checking variables in the struct on failure. Also, when a core extension is loaded as a core extension, the extension variable should be set.
+
+===== Generating core loaders =====
+
+To keep from regenerating the same loading code over and over again, the process will work as follows.
+
+First, we will scan all the functions and collect a list of the individual version numbers of the "deprecated" field.
+
+Then, we generate a number of loader functions for core functions. There will be one "base" function that loads all entrypoints. Then, for each of the version numbers collected above, generate a set of alternative core loader functions up to and including that version number that write functions that haven't been removed up to that version.
+
+As a further optimization, we will have the lower versions call the higher versions. So the base can call the lowest version (where available), the lowest version can call the next-lowest version (where available), and so on. Thus, the base version would only need to store the ''non'' deprecated ones.
+
+Note that these functions must include core ''and'' core extension functions.
+
+So, let's say you have removal on only one verison: 3.1. Therefore, you will write:
+
+* base loader functions for every available GL version. Calling these will have the effect of loading *all* function pointers for that version (and only that version) of OpenGL. Internally, it will load only those functions which were removed in 3.1, and then call the equivalent 3.1 function (if any).
+* loader functions for every GL version up to but not including 3.1. These functions will load only those functions which were *not* removed in 3.1. There will not be functions for GL version 3.1 and 3.2; the base versions will qualify.
+
+To load the core 3.2 context, you call the base 3.2 loader, then call the 3.1 removal functions for everything else.
+
+== Algorithm of gleLoadFunction ==
+
+This function is hand-written, for now.
+
+# Call the function to clear entrypoints.
+# Call the base loading function to get the base entrypoints.
+# Get the OpenGL version.
+# Load the core entrypoints.
+## If version is 2.1 or less, load 2_1.
+## If version is 3.0, load 3.0.
+## If the version is 3.1, check the extension string. If ARB_compatibility is defined, load 3.1 compatibility. Otherwise, load 3.1 core.
+## If the version is 3.2 or greater, check the profile bit and load 3.2 accordingly.
+# For each extension in the string:
+## If the extension has no entry in the map table, continue.
+## If the extension variable for it has already been set to GL_TRUE, do nothing. (it can be set to that because it's a core extension).
+## If the extension has a loader, call it. If the loader returns 1, set the variable to GL_TRUE.
+## If the extension doesn't have a loader, set the variable to GL_TRUE.
+
+== Using the library ==
+
+To initialize the OpenGL core function pointers, the user calls "gleLoadFunctions". This function takes no parameters, and it will load all available extensions and core functions for the [i]actual[/i] version of the OpenGL implementation. This is guaranteed to be greater than or equal to the version the user asked to be created.
+
+The "gleLoadFunctions" will return GL_FALSE if the loading failed.

glload/codegen/LuaAndXMLSpecFormat.txt

+== GL Extensions ==
+
+Here is how the extension loading library will work:
+
+=== Convert to Lua-Form ===
+
+The current extension data format is pretty primitive. So instead, we want to convert it into a Lua-based form.
+
+enumext.spec now contains all of the enumerators, so the format conversion shouldn't be so bad.
+
+Basically, the format should be not entirely unlike what the "collation" functions do. Except that they need to be more true to the .spec format. If we are to replace .specs with this type (or an XML-ized version of it) then we need to deal with the format.
+
+There should also be a converter that converts back to the old format.
+
+==== Format ====
+
+The format is written out by ExtractSpecsToFile.lua. The result is a lua file that, when run will return a table with the following elements:
+
+* extensions: An array of extension name strings, ordered as in enumext.spec.
+* typemap: A table. The keys are the GL types that are used by functions; the values are the actual C types for them.
+* enumerations: An array of enumerators, ordered as in enumext.spec. Each enumerator is a struct defined as:
+** name: String containing the name of the enumerator.
+** value: String number containing the value of the enumerator, or the name of an enumerator to copy from.
+** copy: True if the value is an enumerator to copy from; false if it's a number.
+** version: String in A.B format contining the core version for this enumerator.
+** deprecated: String in A.B format for the version where the enumerator was deprecated.
+** removed: String in A.B format when the enumerator was removed from GL.
+** extension: An array of extension names.
+* funcData: A table containing the following fields:
+** properties: A table of property values. It is a map between property name and values. The value can either be "*" or an array of possible string values that the property can take.
+** passthru: An array of line strings, in the order in gl.spec, for the preamble passthrough data.
+** functions: An array of functions. Each function is a table with:
+*** name: The name of the function.
+*** any of the properties defined in the properties table. This will have values culled from the list of possibles, except if the property was defined as "*", in which case it will be any string.
+*** params: An array of parameters, in the order that they appear in the function prototype. Each parameter is a table with:
+**** name: the name of the parameter.
+**** type: The basic type. Something in the type-map.
+**** input: True if it is an input variable, valse otherwise.
+**** array: True if it is a pointer; false otehrwise.
+**** other: A string containing the other data. Kept for backwards compatibility.
+
+==== Post-Convert ====
+
+The above format is nice, compact and tidy. But there are some useful permutations we can add to make later processing easier. Calling LoadLuaSpec.lua will load the given lua file and add the following entries to the table:
+
+* enumtable: A table of enumerators, indexed by their names. The value are the entries in the main enum array.
+* extdefs: This is a table of extensions, indexed by extension name. Each extension contains:
+** enums: An array of enumerators. These enumerators are the entries in the main enum array.
+** funcs: An array of functions. These functions are the entries in the main funcData.functions array.
+* coredefs: This is a table of core versions, indexed by version name string. Each core contains:
+** enums: An array of enumerators. These enumerators are the entries in the main enum array.
+** funcs: An array of functions. These functions are the entries in the main funcData.functions array.
+* coreexts: A table of core extensions, indexed by extension name. The value of these entries are:
+** name: The core extension's name.
+** version: the version that extension became core in. The version is a string.
+

glload/codegen/MakeAllFiles.lua

+--[[
+Calling dofile on this will generate all of the header and source files needed
+for GLE.
+]]
+
+require "_LoadLuaSpec";
+require "_MakeExtHeaderFile";
+require "_MakeMainHeaderFile";
+require "_MakeMainSourceFile";
+require "_MakeCoreHeaderFile";
+require "_MakeCoreSourceFile";
+require "_util";
+
+local specFileLoc = GetSpecFilePath();
+
+
+
+---------------------------
+--Create standard OpenGL files.
+local specData = LoadLuaSpec(specFileLoc .. "glspec.lua");
+	
+local glPreceedData = {
+	dofile(GetDataFilePath() .. "headerGlProtect.lua"),
+	dofile(GetDataFilePath() .. "glDefStr.lua"),
+	dofile(GetDataFilePath() .. "headerFunc.lua"),
+	footer = {
+		dofile(GetDataFilePath() .. "footerFunc.lua"),
+	},
+}
+
+--Write the external headers.
+local glOutputs = {
+	{"gl_2_1", "2.1", true},
+	{"gl_3_0", "3.0", true},
+	{"gl_3_1", "3.1", true},
+	{"gl_3_1_comp", "3.1", false},
+	{"gl_3_2", "3.2", true},
+	{"gl_3_2_comp", "3.2", false},
+	{"gl_3_3", "3.3", true},
+	{"gl_3_3_comp", "3.3", false},
+	{"gl_4_0", "4.0", true},
+	{"gl_4_0_comp", "4.0", false},
+	{"gl_4_1", "4.1", true},
+	{"gl_4_1_comp", "4.1", false},
+};
+
+for i, output in ipairs(glOutputs) do
+	MakeExtHeaderFile(output[1], specData, "GL", "gl",
+		output[2], output[3], glPreceedData);
+end
+
+local function GetVersionProfIterator()
+	local currIx = 1;
+	
+	return function()
+		if(currIx > #glOutputs) then return nil, nil; end;
+		
+		local currValue = glOutputs[currIx];
+		currIx = currIx + 1;
+		local profile = nil;
+		
+		if(currValue[3]) then profile = "core"; else profile = "compatibility"; end;
+		
+		return currValue[2], profile;
+	end
+end
+
+--Write the internal headers.
+local baseData = {
+	enums = {"VERSION", "EXTENSIONS", "NUM_EXTENSIONS", "CONTEXT_PROFILE_MASK", "CONTEXT_CORE_PROFILE_BIT", "CONTEXT_COMPATIBILITY_PROFILE_BIT", "TRUE", "FALSE"},
+	
+	funcs = {"GetString", "GetStringi", "GetIntegerv"},
+
+	bFuncsAreCore = true,
+	
+	enumPrefix = "GL",
+	
+	preceedData = glPreceedData,
+};
+
+MakeMainHeaderFile("gll_gl_ext", specData, "gl", GetVersionProfIterator(), baseData);
+
+MakeCoreHeaderFile("gll_gl_core", specData, "gl");
+
+--Write the internal source files.
+
+local platformDef = dofile(GetDataFilePath() .. "stdPlatformDef.lua");
+
+MakeMainSourceFile("gll_gl_ext", specData, "GL", "gl", GetVersionProfIterator(), glPreceedData,
+	baseData, {file = "gll_gl_core"});
+
+MakeCoreSourceFile("gll_gl_core", specData, "gl", platformDef);
+
+---------------------------
+--Create WGL files.
+local wglSpecData = LoadLuaSpec(specFileLoc .. "wglspec.lua");
+
+local wglPreceedData = {
+	dofile(GetDataFilePath() .. "wglPreceed.lua"),
+	dofile(GetDataFilePath() .. "wglHeaderFunc.lua"),
+	dofile(GetDataFilePath() .. "glDefStr.lua"),
+}
+
+local wglbaseData = {
+	enums = {},
+	funcs = {"GetExtensionsStringARB"},
+	bFuncsAreCore = false,
+	enumPrefix = "WGL",
+	preceedData = wglPreceedData
+};
+
+
+MakeExtHeaderFile("wgl_exts", wglSpecData, "WGL", "wgl", nil, false, wglPreceedData);
+
+MakeMainHeaderFile("wgll_ext", wglSpecData, "wgl", nil, wglbaseData);
+
+MakeMainSourceFile("wgll_ext", wglSpecData, "WGL", "wgl", nil, wglPreceedData,
+	wglbaseData, nil);
+	
+	
+---------------------------
+--Create GLX files.
+local glxSpecData = LoadLuaSpec(specFileLoc .. "glxspec.lua");
+
+local glxPreceedData = {
+	dofile(GetDataFilePath() .. "glxPreceed.lua"),
+	dofile(GetDataFilePath() .. "glxHeaderFunc.lua"),
+	dofile(GetDataFilePath() .. "glDefStr.lua"),
+}
+
+MakeExtHeaderFile("glx_exts", glxSpecData, "GLX", "glX", nil, false, glxPreceedData);
+
+MakeMainHeaderFile("glxl_ext", glxSpecData, "glX", nil, glxbaseData);
+
+MakeMainSourceFile("glxl_ext", glxSpecData, "GLX", "glX", nil, glxPreceedData,
+	glxbaseData, nil);
+	
+	
+	
+	
+	
+	
+	

glload/codegen/_ExtractEnums.lua

+--[[
+The exported function, ExtractEnums, returns the enum data as follows:
+
+An array of enumerators, ordered as in enumext.spec. Each enumerator is a table that contains
+these fields:
+
+- name: String containing the name of the enumerator.
+- value: String number containing the value of the enumerator, or the name of an enumerator to copy from.
+- copy: True if the value is an enumerator to copy from; false if it's a number.
+- version: String in A.B format contining the core version for this enumerator.
+- deprecated: String in A.B format for the version where the enumerator was deprecated.
+- removed: String in A.B format when the enumerator was removed from GL.
+- extension: An array of extension names.
+]]
+
+require("_line");
+
+--GLOBAL: Bad form, I know, but it's the easiest way to do this.
+local clipPattern = nil;
+
+
+local function AddExtToEnum(enumEntry, extName)
+	if(enumEntry.extensions == nil) then enumEntry.extensions = {}; end;
+	
+	if(clipPattern) then
+		local newExtName = string.match(extName, clipPattern);
+		if(newExtName) then extName = newExtName; end;
+	end
+	
+	table.insert(enumEntry.extensions, extName);
+end
+
+local function FetchEnum(currState, enumName)
+	if(clipPattern) then
+		local newEnumName = string.match(enumName, clipPattern);
+		if(newEnumName) then enumName = newEnumName; end;
+	end
+	
+	if(currState.enumMap[enumName] == nil) then
+		currState.enumMap[enumName] = {};
+		table.insert(currState.enumArray, currState.enumMap[enumName]);
+	end
+
+	local enumEntry = currState.enumMap[enumName];
+	enumEntry.name = enumName;
+	
+	if(currState.extDef.version) then
+		enumEntry.version = currState.extDef.version;
+	else
+		AddExtToEnum(enumEntry, currState.extDef.extName);
+	end
+	
+	if(enumEntry.deprecated == nil) then enumEntry.deprecated = currState.extDef.deprecated; end
+	if(enumEntry.removed == nil) then enumEntry.removed = currState.extDef.removed; end
+	
+	currState.enumMap[enumName] = enumEntry;
+	
+	return enumEntry;
+end
+
+--We process each line with this table. For the line, we match it with the given pattern.
+--If the pattern matches, then we call the associated function. If no patterns match, we skip it.
+--The first parameter to the functions is the current data for our enumerators.
+--The second parameter is the array of matches from the pattern test.
+local procTable =
+{
+	{["pattern"] = "passthru:%s+(.+)", ["func"] = function(currState, matchArray)
+end},
+
+--This pattern is hit when we reach a new extension.
+--This function sets it to be the current extension.
+	{["pattern"] = "(%S+)%s*enum:", ["func"] = function(currState, matchArray)
+		currState.extDef = {};
+		local bHasVersion = false;
+		
+		local baseExtName = string.match(matchArray[1], "(.*)_DEPRECATED$");
+		local testExtName = matchArray[1];
+		
+		if(baseExtName) then testExtName = baseExtName; end;
+
+		local versionNum = string.match(testExtName, "^VERSION_(.*)");
+		if(versionNum) then
+			currState.extDef.version = string.format("%s.%s", string.match(versionNum, "(.*)_(.*)"));
+			bHasVersion = true;
+		end
+		
+		if(baseExtName) then
+			currState.extDef.deprecated = "3.0";
+			currState.extDef.removed = "3.1";
+			if(not bHasVersion) then
+				currState.extDef.extName = baseExtName;
+			end
+		else
+			if(not bHasVersion) then
+				currState.extDef.extName = testExtName;
+			end
+		end
+	end},
+
+--This pattern is hit when we reach an enumeration definition by hexadecimal value.
+	{["pattern"] = "(%S+)%s*=%s*(0x%x+)", ["func"] = function(currState, matchArray)
+		local enumEntry = FetchEnum(currState, matchArray[1]);
+		
+		enumEntry.value = matchArray[2];
+		enumEntry.copy = false;
+	end},
+
+--This pattern is hit when we reach an enumeration definition by decimal value.
+	{["pattern"] = "(%S+)%s*=%s*(%d+)", ["func"] = function(currState, matchArray)
+		local enumEntry = FetchEnum(currState, matchArray[1]);
+		
+		enumEntry.value = matchArray[2];
+		enumEntry.copy = false;
+	end},
+
+--This pattern is hit when we reach an enumeration copy (copy the value from another enum).
+	{["pattern"] = "(%S+)%s*=%s*%S-_(%S+)", ["func"] = function(currState, matchArray)
+		local enumEntry = FetchEnum(currState, matchArray[1]);
+		
+		enumEntry.value = matchArray[2];
+		enumEntry.copy = true;
+	end},
+
+--This pattern is hit when we are saying that the given enum (param #2) is being used in
+--this context, so we should add the current context as extensions or core.
+--If the current context is an extension, then it's possible that
+--the thing using it is a core version.
+	{["pattern"] = "use (%S+)%s*(%S+)", ["func"] = function(currState, matchArray)
+		local enumEntry = FetchEnum(currState, matchArray[2]);
+end},
+};
+
+function ExtractEnums(hInFile, clipPrefix)
+	
+	local state = {};
+	state.enumArray = {};
+	state.enumMap = {};
+	state.FetchEnum = FetchEnum;
+	
+	if(clipPrefix) then
+		clipPattern = string.format("^%s_(.*)", clipPrefix);
+	else
+		clipPattern = nil;
+	end
+
+
+	for strCurrLine in hInFile:lines() do
+		local strOutLine = CullLine(strCurrLine);
+		if(strOutLine) then
+			for i, proc in ipairs(procTable) do
+				local test = {string.match(strOutLine, proc.pattern)};
+				if(#test ~= 0) then
+					proc.func(state, test);
+					break;
+				end;
+			end
+		end
+	end
+	
+	return state.enumArray;
+end
+
+
+

glload/codegen/_ExtractExts.lua

+--[[The funciton ExtractExts takes a file handle to an enumext.spec file. It returns an array of extension names.
+]]
+
+require "_line"
+
+local function IsExtension(heading)
+	if(string.match(heading, "^VERSION.*")) then return false; end;
+	
+	if(string.match(heading, "DEPRECATED$")) then return false; end;
+
+	return true;
+end
+
+function ExtractExts(hInFile, clipPrefix)
+	local ret = {};
+	local headingPattern = "^(%S+)%s*enum:";
+	
+	local clipPattern = nil;
+	if(clipPrefix) then
+		clipPattern = string.format("^%s_(.*)", clipPrefix);
+	end
+
+	for strCurrLine in hInFile:lines() do
+		local strOutLine = CullLine(strCurrLine);
+		if(strOutLine) then
+			local heading = string.match(strOutLine, headingPattern);
+			if(heading) then
+				if(IsExtension(heading)) then
+					if(clipPattern) then
+						local newHeading = string.match(heading, clipPattern);
+						if(newHeading) then heading = newHeading; end;
+					end
+					
+					table.insert(ret, heading);
+				end
+			end
+		end
+	end
+
+	return ret;
+end

glload/codegen/_ExtractFuncs.lua

+--[[The exported function, ExtractFuncs, takes an input file. It returns
+a table that contains these things:
+
+- properties: A table of property values. It is a map between property name and values. The value can either be "*" or an array of possible string values that the property can take.
+- passthru: A string that is the pass-through data that should be put infront of the function definition header.
+- functions: An array of functions. Each function is a table with:
+-- name:
+-- any of the properties defined in the properties table. This will have values culled from the list of possibles, except if the property was defined as "*", in which case it will be any string.
+-- params: An array of parameters, in the order that they are defined as. Each param is a table with:
+--- name: the name of the parameter.
+--- type: The basic type. Something in the type-map.
+--- input: True if it is an input variable, valse otherwise.
+--- array: True if it is a pointer; false otehrwise.
+--- other: A string containing the other data. Kept for backwards compatibility.
+]]
+
+require("_line");
+
+local function StoreParamOptions(param, paramData)
+	local testPattern = "(%S*)%s+(.*)";
+	
+	local glType, rest = string.match(paramData, testPattern);
+	
+	param.type = glType;
+	
+	local input;
+	input, rest = string.match(rest, testPattern);
+	
+	if(input == "in") then
+		param.input = true;
+	else
+		param.input = false;
+	end
+	
+	local oldRest = rest;
+	
+	local arrayKind;
+	arrayKind, rest = string.match(rest, testPattern);
+	
+	if(not arrayKind) then
+		param.kind = oldRest;
+	else
+		param.kind = arrayKind;
+	end
+	
+	if(rest and #rest ~= 0) then
+		param.other = rest;
+	end
+end
+
+
+local function CreateFunc(strFuncName, strParams)
+	local func = {};
+	func.name = strFuncName;
+	func.params = {};
+	func.AddParam = AddParamToFunc;
+
+
+	--Parse the parameters, in order, into paramList.
+	local currParamString = strParams;
+	while((currParamString ~= nil) and (#currParamString ~= 0)) do
+		local strCurrParam;
+		strCurrParam, currParamString = string.match(currParamString, "([%w_]+)(,?%s?.*)");
+
+		local paramData = {};
+		paramData.name = strCurrParam;
+		table.insert(func.params, paramData);
+	end
+	
+	return func;
+end
+
+--If the pattern matches, then the function will be called on that match data.
+local jumpTable = {
+	{pattern = "^required%-props:$", func = function(state, matchArray)
+		state.frontMatter = true;
+	end},
+
+	--Passthrough data.
+	{pattern = "passthru: (.*)", func = function(state, matchArray)
+		if(state.frontMatter) then
+			table.insert(state.funcData.passthru, matchArray[1]);
+		end
+	end},
+	
+	--Front matter
+	{pattern = "(%S*):%s*(.*)", func = function(state, matchArray)
+		if(state.frontMatter) then
+			local paramData = {};
+			state.funcData.properties[matchArray[1]] = paramData;
+			for term in string.gmatch(matchArray[2], "%S*") do
+				if(#term ~= 0) then
+					table.insert(paramData, term);
+				end
+			end
+		end
+	end},
+	
+	--Function definition
+	{pattern = "^([%w_]+)%((.*)%)", func = function(state, matchArray)
+		state.frontMatter = false;
+		state.currFunc = CreateFunc(matchArray[1], matchArray[2]);
+		table.insert(state.funcData.functions, state.currFunc);
+	end},
+
+	--Parameter Properties
+	{pattern = "^\tparam%s+(%S*)%s+(.*)", func = function(state, matchArray)
+		local bFound = false;
+		
+		for count = 1, #state.currFunc.params, 1 do
+			if(state.currFunc.params[count].name == matchArray[1]) then
+				StoreParamOptions(state.currFunc.params[count], matchArray[2]);
+				bFound = true;
+				break;
+			end
+		end
+		
+		if(not bFound) then
+			print(string.format("The func \"%s\" does not have parameter \"%s\".",
+				state.currFunc.name, matchArray[1]));
+			return true;
+		end;
+	end},
+	
+	--Non-param Properties
+	{pattern = "^\t(%S*)%s+(%S*)", func = function(state, matchArray)
+		state.currFunc[matchArray[1]] = matchArray[2];
+	end},
+}
+
+function ExtractFuncs(hFile)
+	local funcData = {};
+	funcData.properties = {};
+	funcData.passthru = {};
+	funcData.functions = {};
+	
+	local state = {};
+	state.funcData = funcData;
+	
+	for currLine in hFile:lines() do
+		local outLine = CullLine(currLine);
+		
+		if(outLine) then
+			for i, proc in ipairs(jumpTable) do
+				local parseArray = {string.match(outLine, proc.pattern);}
+				if(parseArray[1]) then
+					local bRet = proc.func(state, parseArray);
+					if(bRet) then
+						print("Bad line: " .. outLine);
+					end
+				end
+			end
+		end
+	end
+	
+	return state.funcData;
+end
+

glload/codegen/_ExtractSpecsToFile.lua

+--[[This file exposes a function that will write a Lua-based spec file. It takes a destination
+file and table of 3 files:
+
+-glspec: the gl.spec file.
+-enumext: the enumext.spec file.
+-gltm: the gl.tm file.
+
+The destination file is a lua file that, when "dofile" is run on it, returns the table. The table
+is formatted as follows:
+
+- extensions: A table formatted as in ExtractExts.
+- enumerations: A table formatted as in ExtractEnums.
+- typemap: A table formatted as in ExtractTypes.
+- funcData: A table formatted as in ExtractFuncs.
+]]
+
+require "_ExtractExts"
+require "_ExtractEnums"
+require "_ExtractTypes"
+require "_ExtractFuncs"
+require "_TableWriter"
+require "_util"
+
+
+function ExtractSpecsToFile(outFilename, inputFiles, clipPrefix)
+	local extractedData = {};
+	
+	local hFile = io.open(GetSpecFilePath() .. inputFiles.enumext, "r");
+	if(not hFile) then
+		print(string.format("Could not open enumext file: '%s'", inputFiles.enumext));
+		return;
+	end
+	extractedData.extensions = ExtractExts(hFile, clipPrefix);
+	hFile:close();
+
+	hFile = io.open(GetSpecFilePath() .. inputFiles.enumext, "r");
+	if(not hFile) then
+		print(string.format("Could not open enumext file: '%s'", inputFiles.enumext));
+		return;
+	end
+	extractedData.enumerations = ExtractEnums(hFile, clipPrefix);
+	hFile:close();
+
+	hFile = io.open(GetSpecFilePath() .. inputFiles.gltm, "r");
+	if(not hFile) then
+		print(string.format("Could not open gltm file: '%s'", inputFiles.gltm));
+		return;
+	end
+	extractedData.typemap = ExtractTypes(hFile);
+	hFile:close();
+
+	hFile = io.open(GetSpecFilePath() .. inputFiles.glspec, "r");
+	if(not hFile) then
+		print(string.format("Could not open glspec file: '%s'", inputFiles.glspec));
+		return;
+	end
+	extractedData.funcData = ExtractFuncs(hFile);
+	hFile:close();
+	
+	hFile = io.open(GetSpecFilePath() .. outFilename, "w");
+	if(not hFile) then
+		print(string.format("Could not open the output file: '%s'", outFilename));
+		return;
+	end
+	hFile:write("return ");
+	WriteTable(hFile, extractedData);
+	hFile:write(";\n");
+	hFile:close();
+end
+
+

glload/codegen/_ExtractTypes.lua

+--[[ This function takes a handle to a .tm file, and returns a table. The keys for the table are
+the GL-generic types, and the values are the actual C++ types for them.
+]]
+
+require("_line");
+
+function ExtractTypes(hInFile)
+	local typemapPattern = "^(%S-),.-,.-,%s-(%S.-),";
+	
+	local typeMap = {};
+
+	for strCurrLine in hInFile:lines() do
+		local strOutLine = CullLine(strCurrLine);
+		
+		if(strOutLine) then
+			local glType, realType = string.match(strOutLine, typemapPattern);
+			if(glType and realType) then
+				if(typeMap[glType]) then
+					print("typemap duplicate: " .. strOutLine);
+				else
+					typeMap[glType] = realType;
+				end
+			else
+				print("bad typemap line: " .. strOutLine);
+			end
+		end
+	end
+	
+	return typeMap;
+end

glload/codegen/_LoadLuaSpec.lua

+--[[
+The function, LoadLuaSpec exposed here will load a spec.lua file. It takes a filename
+pointing to a spec.lua file.
+
+This function will also add some features to the object before returning it.
+
+The format will be as defined in ConvertAllSpecFilesToLua, except for the following:
+
+- extdefs: This is a table of extensions, indexed by extension name.
+	Each entry contains:
+-- enums: An array of enumerators. These enumerators are the entries in the main enum array.
+-- funcs: An array of functions. These functions are the entries in the main funcData array.
+- coredefs: This is a table of core versions, indexed by version name string
+	"1.1" is the first.
+-- enums: An array of enumerators. These enumerators are the entries in the main enum array.
+-- funcs: An array of functions. These functions are the entries in the main funcData array.
+- enumtable: A table of enumerators, indexed by their names.
+- coreexts: A table of core extensions, indexed by extension name. The value of these entries are:
+-- name: The core extension's name.
+-- version: the version that extension became core in. The version is a string.
+
+
+All enumerators and functions are found in one of these two lists. Some of them are in both.
+
+Other changes are:
+- All functions that would have the 1.0 version have it changed to 1.1. This makes the data match the enums.
+- The "void" type in the typemap maps to "void".
+- Fixes for certain extensions. Certain extensions are non-core, but the enums and functions
+	have no suffixes as if they were core.
+]]
+
+local listOfCoreVersions = dofile("data/listOfCoreVersions.lua");
+
+local listOfNonCoreFixes = 
+{
+	"ARB_sample_shading",
+	"ARB_draw_buffers_blend",
+	"ARB_texture_cube_map_array",
+};
+
+local listOfExtensionsToRemove =
+{
+    "SGIX_video_source",
+    "SGIX_dmbuffer",
+    "SGIX_hyperpipe",
+};
+
+function LoadLuaSpec(luaFilename)
+	local specData = dofile(luaFilename);
+
+	specData.extdefs = {};
+	specData.coredefs = {};
+	specData.enumtable = {};
+	local extdefs = specData.extdefs;
+	local coredefs = specData.coredefs;
+	local enumtable = specData.enumtable;
+	
+	--HACK! Change 1.0 version in functions to 1.1, to match enums.
+	for i, func in ipairs(specData.funcData.functions) do
+		if(func.version == "1.0") then func.version = "1.1"; end;
+	end
+	
+	--HACK! Change "void" in the typemap to map to "void".
+	specData.typemap.void = "void";
+	
+	--HACK! Add suffixes to functions and enums for these extensions.
+	for i, extName in ipairs(listOfNonCoreFixes) do
+		for j, func in ipairs(specData.funcData.functions) do
+			if(func.category == extName) then
+				func.name = func.name .. "ARB";
+			end
+		end
+		for j, enum in ipairs(specData.enumerations) do
+			if(enum.extensions) then
+				for k, enumExt in ipairs(enum.extensions) do
+					if(enumExt == extName) then
+						enum.name = enum.name .. "_ARB";
+					end
+				end
+			end
+		end
+	end
+	
+	--HACK! Remove certain offensive extensions.
+	local toRemove = {}
+	for i, ext in ipairs(specData.extensions) do
+	    for j, test in ipairs(listOfExtensionsToRemove) do
+	        if(ext == test) then
+	            table.insert(toRemove, 1, i);
+	            break;
+	        end
+	    end
+	end
+	
+	for i, index in ipairs(toRemove) do
+	    table.remove(specData.extensions, index);
+	end
+	
+	toRemove = {}
+	for i, enum in ipairs(specData.enumerations) do
+		if(enum.extensions) then
+		    for j, enumExt in ipairs(enum.extensions) do
+		        local bBreak = false;
+	            for k, test in ipairs(listOfExtensionsToRemove) do
+	                if(enumExt == test) then
+	                    table.insert(toRemove, 1, i);
+	                    bBreak = true;
+	                    break;
+	                end
+	            end
+	            if(bBreak) then break; end
+		    end
+		end
+	end
+	
+	for i, index in ipairs(toRemove) do
+	    table.remove(specData.enumerations, index);
+	end
+	
+	toRemove = {}
+    for i, func in ipairs(specData.funcData.functions) do
+	    for j, test in ipairs(listOfExtensionsToRemove) do
+	        if(ext == func.category) then
+	            table.insert(toRemove, 1, i);
+	            break;
+	        end
+	    end
+    end
+
+	for i, index in ipairs(toRemove) do
+	    table.remove(specData.funcData.functions, index);
+	end
+	
+	
+	
+	
+	local function GetCore(version)
+		if(not coredefs[version]) then
+			local coredef = {};
+			coredefs[version] = coredef;
+			coredef.enums = {};
+			coredef.funcs = {};
+		end
+		
+		return coredefs[version];
+	end
+	
+	local function GetExt(extName)
+		if(not extdefs[extName]) then
+			local extdef = {};
+			extdefs[extName] = extdef;
+			extdef.enums = {};
+			extdef.funcs = {};
+		end
+		
+		return extdefs[extName];
+	end
+
+	--Add all extensions to the extdefs.
+	for	i, extName in ipairs(specData.extensions) do
+		GetExt(extName);
+	end
+	
+	for i, enum in ipairs(specData.enumerations) do
+		enumtable[enum.name] = enum;
+		
+		if(enum.extensions) then
+			for k, extName in ipairs(enum.extensions) do
+				table.insert(GetExt(extName).enums, enum);
+			end
+		end
+		
+		if(enum.version) then
+			table.insert(GetCore(enum.version).enums, enum);
+		end
+	end
+
+	for i, func in ipairs(specData.funcData.functions) do
+		--This is here to make sure that the category is an actual extension,
+		--not a verison number.
+		if(extdefs[func.category]) then
+			table.insert(GetExt(func.category).funcs, func);
+		end
+	
+		if(func.version) then
+			if(not func.category or string.match(func.category, "^VERSION")) then
+				local versionVal = string.gsub(func.category, "VERSION_(%d+)_(%d+).*", "%1%.%2");
+				--HACK!
+				if(versionVal == "1.0") then versionVal = "1.1" end;
+				table.insert(GetCore(versionVal).funcs, func);
+			end
+		end
+	end
+	
+	specData.coreexts = dofile(GetDataFilePath() .. "coreExtList.lua");
+
+	return specData;
+end
+

glload/codegen/_MakeCoreHeaderFile.lua

+--[[
+The function MakeCoreHeaderFile will generate the core source file.
+
+This file will contain all of the core function pointers (including core extensions) in a big struct. It also exposes a function that will set these function pointers from the default version of OpenGL.
+
+The function is called "void [funcPrefix]eIntCoreInit();"
+
+This exists to fix the "core function" problem. Windows, for examples, defines all of the 1.1 entrypoints as regular functions. Thus, calling wglGetProcAddress will not retrieve those functions. We must instead get pointers to those functions manually. They get put into this struct.
+
+The above function will fill in the pointers that standard GL provides, while NULL-ing out things that aren't statically defined.
+
+You MUST include a file that has all of the typedefs before including this file.
+]]
+
+require "_makeHelpers"
+require "_util"
+
+function MakeCoreHeaderFile(outFilename, specData, funcPrefix)
+	local hFile = io.open(GetSourcePath() .. outFilename .. ".h", "w");
+	if(not hFile) then
+		print("Could not open the output file\"" .. GetSourcePath() .. outFilename .. "\".\n");
+		return;
+	end
+	
+	local defineName = string.upper(outFilename) .. "_H";
+
+	hFile:write(GetFileIncludeGuardStart(defineName));
+	hFile:write("\n");
+	
+	hFile:write(GetExternCStart());
+	hFile:write("\n");
+	
+	hFile:write("\n");
+
+	--Collect all of the appropriate functions.
+	local funcList = Make.FetchAllCoreFunctions(specData);
+	
+	hFile:write(string.format("typedef struct %s_s\n", Make.GetCoreStructType(funcPrefix)));
+	hFile:write("{\n");
+	
+	--Write out the struct values.
+	for i, func in ipairs(funcList) do
+		hFile:write(string.format("\tvoid *%s;\n",
+			Make.GetCoreStructMemberName(func, funcPrefix)
+		));
+	end
+
+	WriteForm(hFile, "}%s;\n", Make.GetCoreStructType(funcPrefix));
+	hFile:write("\n");
+	
+	--Write the extern of the struct definition.
+	hFile:write(string.format("extern %s %s;\n", Make.GetCoreStructType(funcPrefix),
+		Make.GetCoreStructVarName(funcPrefix)));
+
+	hFile:write("\n");
+	
+	WriteFormatted(hFile, "void %s();\n", Make.GetCoreInitFuncName(funcPrefix));
+		
+	hFile:write("\n");
+
+	hFile:write(GetExternCEnd());
+	hFile:write("\n");
+
+	hFile:write(GetFileIncludeGuardEnd(defineName));
+	hFile:write("\n");
+	
+	hFile:close();
+end

glload/codegen/_MakeCoreSourceFile.lua

+--[[
+The function MakeCoreSourceFile will generate the core source file.
+
+The file will implement the function exposed by MakeCoreHeaderFile.
+
+Because the implementation of this is platform-specific, there must be a way to determine which versions are available in the core gl.h file. To do this, you provide a special parameter: platformDef.
+
+The platformDef parameter is an array of platform definitions. Each entry in the array has the following:
+
+* define: the string name of the #define that is used to control this.
+* statements: a list of strings, each of which is a statement. These should be added towards the top of the file; they must include the standard gl.h.
+* versions: a list of versions (in string form) that the included files define.
+]]
+
+require "_makeHelpers"
+require "_util"
+
+
+function MakeCoreSourceFile(outFilename, specData, funcPrefix, platformDef)
+	local hFile = io.open(GetSourcePath() .. outFilename .. ".c", "w");
+	if(not hFile) then
+		print("Could not open the output file\"" .. GetSourcePath() .. outFilename .. ".c\".\n");
+		return;
+	end
+	
+	hFile:write([[#include <stdlib.h>