Commits

Jason McKesson committed 59e68e9

Added a mesh loading system to the framework.

Comments (0)

Files changed (6)

Documents/Positioning/Tutorial 06.xml

                 </inlineequation>.</para>
             <para>In the case of the scalar inverse, this is very easy to compute: <inlineequation>
                     <mathphrase>Y = 1/X</mathphrase>
-                </inlineequation>. However, even in this case, there are values of X for which there
-                is no multiplicative inverse. Well, one value of X: 0.</para>
+                </inlineequation>. Even in this case, there are values of X for which there is no
+                multiplicative inverse. OK, there's <emphasis>one</emphasis> value of X: 0.</para>
             <para>The case of the inverse matrix is much more complicated. Just as with the scalar
                 inverse, there are matrices that have no inverse. Unlike the scalar case, there are
                 a <emphasis>lot</emphasis> of matrices with no inverse. Also, computing the inverse
                 matrix. For a scale matrix, take the reciprocal of the scale along each axis.</para>
             <para>To take the inverse of a sequence of matrices, you can take the inverse of each of
                 the component matrices. But you have to do the matrix multiplication in
-                    <emphasis>reverse</emphasis> order. So the inverse matrix for the sequence <inlineequation>
-                    <mathphrase>TRS</mathphrase>
-                </inlineequation> is <inlineequation>
-                    <mathphrase>S<superscript>-1</superscript>R<superscript>-1</superscript>T<superscript>-1</superscript></mathphrase>
+                    <emphasis>reverse</emphasis> order. So if we have <inlineequation>
+                    <mathphrase>M = TRS</mathphrase>
+                </inlineequation>, then M<superscript>-1</superscript> is <inlineequation>
+                    <mathphrase>M<superscript>-1</superscript> =
+                            S<superscript>-1</superscript>R<superscript>-1</superscript>T<superscript>-1</superscript></mathphrase>
                 </inlineequation>.</para>
         </section>
         <section>

Documents/Tutorial Documents.xpr

         </folder>
         <file name="Building%20the%20Tutorials.xml"/>
         <file name="cssDoc.txt"/>
+        <file name="meshFormat.rnc"/>
         <file name="Outline.xml"/>
         <file name="Tutorials.xml"/>
     </projectTree>
+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="../Documents/meshFormat.rnc" type="compact"?>
+<mesh xmlns="http://www.arcsynthesis.com/gltut/mesh">
+    <attribute index="0" type="float" size="4">
+        0.75 0.75 0.0 1.0
+        0.75 -0.75 0.0 1.0
+        -0.75 -0.75 0.0 1.0
+    </attribute>
+    <arrays cmd="triangles" start="0" count="3"/>
+</mesh>
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
 #include <glloader/gl_3_2_comp.h>
-#include <glloader/wgl_exts.h>
-#include <glloader/gle.h>
 #include <GL/freeglut.h>
+#include "../framework/framework.h"
 
-/* report GL errors, if any, to stderr */
-void checkError(const char *functionName)
+
+GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile)
 {
-	GLenum error;
-	while (( error = glGetError() ) != GL_NO_ERROR) {
-		fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
+	GLuint shader = glCreateShader(eShaderType);
+	const char *strFileData = strShaderFile.c_str();
+	glShaderSource(shader, 1, &strFileData, NULL);
+
+	glCompileShader(shader);
+
+	GLint status;
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+	if (status == GL_FALSE)
+	{
+		GLint infoLogLength;
+		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
+		glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
+
+		const char *strShaderType = NULL;
+		switch(eShaderType)
+		{
+		case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
+		case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
+		case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
+		}
+
+		fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
+		delete[] strInfoLog;
+	}
+
+	return shader;
+}
+
+GLuint CreateProgram(const std::vector<GLuint> &shaderList)
+{
+	GLuint program = glCreateProgram();
+
+	for(size_t iLoop = 0; iLoop < shaderList.size(); iLoop++)
+		glAttachShader(program, shaderList[iLoop]);
+
+	glLinkProgram(program);
+
+	GLint status;
+	glGetProgramiv (program, GL_LINK_STATUS, &status);
+	if (status == GL_FALSE)
+	{
+		GLint infoLogLength;
+		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
+		glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
+		fprintf(stderr, "Linker failure: %s\n", strInfoLog);
+		delete[] strInfoLog;
+	}
+
+	return program;
+}
+
+GLuint theProgram;
+
+const std::string strVertexShader(
+								  "#version 330\n"
+								  "layout(location = 0) in vec4 position;\n"
+								  "void main()\n"
+								  "{\n"
+								  "   gl_Position = position;\n"
+								  "}\n"
+								  );
+
+const std::string strFragmentShader(
+									"#version 330\n"
+									"out vec4 outputColor;\n"
+									"void main()\n"
+									"{\n"
+									"   outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n"
+									"}\n"
+									);
+
+void InitializeProgram()
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(CreateShader(GL_VERTEX_SHADER, strVertexShader));
+	shaderList.push_back(CreateShader(GL_FRAGMENT_SHADER, strFragmentShader));
+
+	theProgram = CreateProgram(shaderList);
+}
+
+const float vertexPositions[] = {
+	0.75f, 0.75f, 0.0f, 1.0f,
+	0.75f, -0.75f, 0.0f, 1.0f,
+	-0.75f, -0.75f, 0.0f, 1.0f,
+};
+
+GLuint positionBufferObject;
+GLuint vao;
+
+
+void InitializeVertexBuffer()
+{
+	glGenBuffers(1, &positionBufferObject);
+
+	glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+const char *g_strTestFloats = " \n-10.0 10.0 23.4\n4.32 -4 -5 ";
+Framework::Mesh *g_theMesh = NULL;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	try
+	{
+		g_theMesh = new Framework::Mesh("mesh.xml");
+	}
+	catch(std::exception &except)
+	{
+		g_theMesh = NULL;
+		printf(except.what());
+	}
+
+	InitializeProgram();
+	InitializeVertexBuffer();
+
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+}
+
+//Called to update the display.
+//You should call glutSwapBuffers after all of your rendering to display what you rendered.
+//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
+void display()
+{
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glUseProgram(theProgram);
+
+	if(g_theMesh)
+		g_theMesh->Render();
+/*
+	glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
+	glEnableVertexAttribArray(0);
+	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
+
+	glDrawArrays(GL_TRIANGLES, 0, 3);
+*/
+
+	glDisableVertexAttribArray(0);
+	glUseProgram(0);
+
+	glutSwapBuffers();
+}
+
+//Called whenever the window is resized. The new window size is given, in pixels.
+//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
+void reshape (int w, int h)
+{
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+}
+
+//Called whenever a key on the keyboard was pressed.
+//The key is given by the ''key'' parameter, which is in ASCII.
+//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
+//exit the program.
+void keyboard(unsigned char key, int x, int y)
+{
+	switch (key)
+	{
+	case 27:
+		delete g_theMesh;
+		glutLeaveMainLoop();
+		break;
 	}
 }
 
-/* vertex array data for a colored 2D triangle, consisting of RGB color values
-and XY coordinates */
-const GLfloat varray[] = {
-	1.0f, 0.0f, 0.0f, /* red */
-	5.0f, 5.0f,       /* lower left */
 
-	0.0f, 1.0f, 0.0f, /* green */
-	25.0f, 5.0f,      /* lower right */
-
-	0.0f, 0.0f, 1.0f, /* blue */
-	5.0f, 25.0f       /* upper left */
-};
-
-/* ISO C somehow enforces this silly use of 'enum' for compile-time constants */
-enum {
-	numColorComponents = 3,
-	numVertexComponents = 2,
-	stride = sizeof(GLfloat) * (numColorComponents + numVertexComponents),
-	numElements = sizeof(varray) / stride
-};
-
-/* the name of the vertex buffer object */
-GLuint vertexBufferName;
-
-void initBuffer(void)
-{
-	glGenBuffers (1, &vertexBufferName);
-	glBindBuffer (GL_ARRAY_BUFFER, vertexBufferName);
-	glBufferData (GL_ARRAY_BUFFER, sizeof(varray), varray, GL_STATIC_DRAW);
-	checkError ("initBuffer");
-}
-
-const GLchar *vertexShaderSource[] = {
-	"#version 140\n",
-	"uniform mat4 fg_ProjectionMatrix;\n",
-	"in vec4 fg_Color;\n",
-	"in vec4 fg_Vertex;\n",
-	"smooth out vec4 fg_SmoothColor;\n",
-	"void main()\n",
-	"{\n",
-	"   fg_SmoothColor = fg_Color;\n",
-	"   gl_Position = fg_ProjectionMatrix * fg_Vertex;\n",
-	"}\n"
-};
-
-const GLchar *fragmentShaderSource[] = {
-	"#version 140\n",
-	"smooth in vec4 fg_SmoothColor;\n",
-	"out vec4 fg_FragColor;\n",
-	"void main(void)\n",
-	"{\n",
-	"   fg_FragColor = fg_SmoothColor;\n",
-	"}\n"
-};
-
-void compileAndCheck(GLuint shader)
-{
-	GLint status;
-	glCompileShader (shader);
-	glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
-	if (status == GL_FALSE) {
-		GLint infoLogLength;
-		GLchar *infoLog;
-		glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
-		infoLog = (GLchar*) malloc (infoLogLength);
-		glGetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
-		fprintf (stderr, "compile log: %s\n", infoLog);
-		free (infoLog);
-	}
-}
-
-GLuint compileShaderSource(GLenum type, GLsizei count, const GLchar **string)
-{
-	GLuint shader = glCreateShader (type);
-	glShaderSource (shader, count, string, NULL);
-	compileAndCheck (shader);
-	return shader;
-}
-
-void linkAndCheck(GLuint program)
-{
-	GLint status;
-	glLinkProgram (program);
-	glGetProgramiv (program, GL_LINK_STATUS, &status);
-	if (status == GL_FALSE) {
-		GLint infoLogLength;
-		GLchar *infoLog;
-		glGetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLogLength);
-		infoLog = (GLchar*) malloc (infoLogLength);
-		glGetProgramInfoLog (program, infoLogLength, NULL, infoLog);
-		fprintf (stderr, "link log: %s\n", infoLog);
-		free (infoLog);
-	}
-}
-
-GLuint createProgram(GLuint vertexShader, GLuint fragmentShader)
-{
-	GLuint program = glCreateProgram ();
-	if (vertexShader != 0) {
-		glAttachShader (program, vertexShader);
-	}
-	if (fragmentShader != 0) {
-		glAttachShader (program, fragmentShader);
-	}
-	linkAndCheck (program);
-	return program;
-}
-
-GLuint fgProjectionMatrixIndex;
-GLuint fgColorIndex;
-GLuint fgVertexIndex;
-
-void initShader(void)
-{
-	const GLsizei vertexShaderLines = sizeof(vertexShaderSource) / sizeof(GLchar*);
-	GLuint vertexShader =
-		compileShaderSource (GL_VERTEX_SHADER, vertexShaderLines, vertexShaderSource);
-
-	const GLsizei fragmentShaderLines = sizeof(fragmentShaderSource) / sizeof(GLchar*);
-	GLuint fragmentShader =
-		compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
-
-	GLuint program = createProgram (vertexShader, fragmentShader);
-
-	glUseProgram (program);
-
-	fgProjectionMatrixIndex = glGetUniformLocation(program, "fg_ProjectionMatrix");
-
-	fgColorIndex = glGetAttribLocation(program, "fg_Color");
-	glEnableVertexAttribArray (fgColorIndex);
-
-	fgVertexIndex = glGetAttribLocation(program, "fg_Vertex");
-	glEnableVertexAttribArray (fgVertexIndex);
-
-	checkError ("initShader");
-}
-
-void initRendering(void)
-{
-	glClearColor (0.0, 0.0, 0.0, 0.0);
-	checkError ("initRendering");
-}
-
-void dumpInfo(void)
-{
-	printf ("Vendor: %s\n", glGetString (GL_VENDOR));
-	printf ("Renderer: %s\n", glGetString (GL_RENDERER));
-	printf ("Version: %s\n", glGetString (GL_VERSION));
-	printf ("GLSL: %s\n", glGetString (GL_SHADING_LANGUAGE_VERSION));
-	checkError ("dumpInfo");
-}
-
-void init(void) 
-{
-	dumpInfo ();
-
-	initBuffer ();
-	initShader ();
-	initRendering ();
-}
-
-const GLvoid *bufferObjectPtr (GLsizei index)
-{
-	return (const GLvoid *) (((char *) NULL) + index);
-}
-
-GLfloat projectionMatrix[16];
-
-void triangle(void)
-{
-	glUniformMatrix4fv (fgProjectionMatrixIndex, 1, GL_FALSE, projectionMatrix);
-
-	glBindBuffer (GL_ARRAY_BUFFER, vertexBufferName);
-	glVertexAttribPointer (fgColorIndex, numColorComponents, GL_FLOAT, GL_FALSE,
-		stride, bufferObjectPtr (0));
-	glVertexAttribPointer (fgVertexIndex, numVertexComponents, GL_FLOAT, GL_FALSE,
-		stride, bufferObjectPtr (sizeof(GLfloat) * numColorComponents));
-	glDrawArrays(GL_TRIANGLES, 0, numElements);
-	checkError ("triangle");
-}
-
-void display(void)
-{
-	glClear (GL_COLOR_BUFFER_BIT);
-	triangle ();
-	checkError ("display");
-	glutSwapBuffers();
-}
-
-void loadOrthof(GLfloat *m, GLfloat l, GLfloat r, GLfloat b, GLfloat t,
-				GLfloat n, GLfloat f)
-{
-	m[ 0] = 2.0f / (r - l);
-	m[ 1] = 0.0f;
-	m[ 2] = 0.0f;
-	m[ 3] = 0.0f;
-
-	m[ 4] = 0.0f;
-	m[ 5] = 2.0f / (t - b);
-	m[ 6] = 0.0f;
-	m[ 7] = 0.0f;
-
-	m[ 8] = 0.0f;
-	m[ 9] = 0.0f;
-	m[10] = -2.0f / (f - n);
-	m[11] = 0.0f;
-
-	m[12] = -(r + l) / (r - l);
-	m[13] = -(t + b) / (t - b);
-	m[14] = -(f + n) / (f - n);
-	m[15] = 1.0f;
-}
-
-void loadOrtho2Df(GLfloat *m, GLfloat l, GLfloat r, GLfloat b, GLfloat t)
-{
-	loadOrthof (m, l, r, b, t, -1.0f, 1.0f);
-}
-
-void reshape (int w, int h)
-{
-	glViewport (0, 0, (GLsizei) w, (GLsizei) h);
-	if (w <= h) {
-		loadOrtho2Df (projectionMatrix, 0.0f, 30.0f, 0.0f, 30.0f * (GLfloat) h/(GLfloat) w);
-	} else {
-		loadOrtho2Df (projectionMatrix, 0.0f, 30.0f * (GLfloat) w/(GLfloat) h, 0.0f, 30.0f);
-	}
-	checkError ("reshape");
-}
-
-void keyboard(unsigned char key, int x, int y)
-{
-	switch (key) {
-	  case 27:
-		  glutLeaveMainLoop();
-		  break;
-	}
-}

framework/framework.cpp

 #include <vector>
 #include <fstream>
 #include <sstream>
+#include <functional>
+#include <algorithm>
 #include <glloader/gl_3_2_comp.h>
 #include <glloader/wgl_exts.h>
 #include <glloader/gle.h>
 #include <GL/freeglut.h>
+#include <tinyxml.h>
 #include "framework.h"
 
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
 
 namespace Framework
 {
 		return program;
 	}
 
+	struct RenderCmd
+	{
+		bool bIsIndexedCmd;
+		GLenum ePrimType;
+		GLuint start;
+		GLuint elemCount;
+		GLenum eIndexDataType;	//Only if bIsIndexedCmd is true.
+		int primRestart;		//Only if bIsIndexedCmd is true.
+
+		void Render()
+		{
+			if(bIsIndexedCmd)
+				glDrawElements(ePrimType, elemCount, eIndexDataType, (void*)start);
+			else
+				glDrawArrays(ePrimType, start, elemCount);
+		}
+	};
+
+	union AttribData
+	{
+		float fValue;
+		GLuint uiValue;
+		GLint iValue;
+		GLushort usValue;
+		GLshort sValue;
+		GLubyte ubValue;
+		GLbyte bValue;
+	};
+
+	struct PrimitiveType
+	{
+		const char *strPrimitiveName;
+		GLenum eGLPrimType;
+	};
+
+	struct AttribType
+	{
+		const char *strNameFromFile;
+		bool bNormalized;
+		GLenum eGLType;
+		int iNumBytes;
+		void(*ParseFunc)(std::vector<AttribData> &, std::istream &);
+		void(*WriteToBuffer)(GLenum, const std::vector<AttribData> &, int, size_t);
+	};
+
+#define PARSE_ARRAY_FUNCDEF(attribDataValue, funcName)\
+	void funcName(std::vector<AttribData> &outputData, std::istream &inStream)\
+	{\
+		inStream.seekg(0, std::ios_base::beg);\
+		inStream >> std::skipws;\
+\
+		while(!inStream.eof() && inStream.good())\
+		{\
+			AttribData theValue;\
+			inStream >> theValue.attribDataValue >> std::ws;\
+			if(inStream.fail())\
+				throw std::exception("Parse error in array data stream.");\
+			outputData.push_back(theValue);\
+		}\
+	}\
+
+	void WriteFloatsToBuffer(GLenum eBuffer, const std::vector<AttribData> &theData,
+		int iSize, size_t iOffset)
+	{
+		std::vector<float> tempBuffer;
+		tempBuffer.reserve(theData.size());
+
+		for(size_t iLoop = 0; iLoop < theData.size(); iLoop++)
+			tempBuffer.push_back(theData[iLoop].fValue);
+
+		glBufferSubData(eBuffer, iOffset, tempBuffer.size() * sizeof(float), &tempBuffer[0]);
+	}
+
+#define WRITE_ARRAY_FUNCDEF(attribDataValue, attribType, funcName) \
+	void funcName(GLenum eBuffer, const std::vector<AttribData> &theData, \
+		int iSize, size_t iOffset) \
+	{ \
+		std::vector<attribType> tempBuffer; \
+		tempBuffer.reserve(theData.size()); \
+ \
+		for(size_t iLoop = 0; iLoop < theData.size(); iLoop++) \
+			tempBuffer.push_back(theData[iLoop].attribDataValue); \
+ \
+		glBufferSubData(eBuffer, iOffset, tempBuffer.size() * sizeof(attribType), &tempBuffer[0]); \
+	} \
+
+
+	PARSE_ARRAY_FUNCDEF(fValue,		ParseFloats);
+	PARSE_ARRAY_FUNCDEF(uiValue,	ParseUInts);
+	PARSE_ARRAY_FUNCDEF(iValue,		ParseInts);
+	PARSE_ARRAY_FUNCDEF(usValue,	ParseUShorts);
+	PARSE_ARRAY_FUNCDEF(sValue,		ParseShorts);
+	PARSE_ARRAY_FUNCDEF(ubValue,	ParseUBytes);
+	PARSE_ARRAY_FUNCDEF(bValue,		ParseBytes);
+
+	WRITE_ARRAY_FUNCDEF(fValue,		float,		WriteFloats);
+	WRITE_ARRAY_FUNCDEF(uiValue,	GLuint,		WriteUInts);
+	WRITE_ARRAY_FUNCDEF(iValue,		GLint,		WriteInts);
+	WRITE_ARRAY_FUNCDEF(usValue,	GLushort,	WriteUShorts);
+	WRITE_ARRAY_FUNCDEF(sValue,		GLshort,	WriteShorts);
+	WRITE_ARRAY_FUNCDEF(ubValue,	GLubyte,	WriteUBytes);
+	WRITE_ARRAY_FUNCDEF(bValue,		GLbyte,		WriteBytes);
+
+
+	namespace
+	{
+		const AttribType g_allAttributeTypes[] =
+		{
+			{"float",		false,	GL_FLOAT,			sizeof(GLfloat),	ParseFloats,	WriteFloats},
+			{"int",			false,	GL_INT,				sizeof(GLint),		ParseInts,		WriteInts},
+			{"uint",		false,	GL_UNSIGNED_INT,	sizeof(GLuint),		ParseUInts,		WriteUInts},
+			{"norm-int",	true,	GL_INT,				sizeof(GLint),		ParseInts,		WriteInts},
+			{"norm-uint",	true,	GL_UNSIGNED_INT,	sizeof(GLuint),		ParseUInts,		WriteUInts},
+			{"short",		false,	GL_SHORT,			sizeof(GLshort),	ParseShorts,	WriteShorts},
+			{"ushort",		false,	GL_UNSIGNED_SHORT,	sizeof(GLushort),	ParseUShorts,	WriteUShorts},
+			{"norm-short",	true,	GL_SHORT,			sizeof(GLshort),	ParseShorts,	WriteShorts},
+			{"norm-ushort",	true,	GL_UNSIGNED_SHORT,	sizeof(GLushort),	ParseUShorts,	WriteUShorts},
+			{"byte",		false,	GL_BYTE,			sizeof(GLbyte),		ParseBytes,		WriteBytes},
+			{"ubyte",		false,	GL_UNSIGNED_BYTE,	sizeof(GLubyte),	ParseUBytes,	WriteUBytes},
+			{"norm-byte",	true,	GL_BYTE,			sizeof(GLbyte),		ParseBytes,		WriteBytes},
+			{"norm-ubyte",	true,	GL_UNSIGNED_BYTE,	sizeof(GLubyte),	ParseUBytes,	WriteUBytes},
+		};
+
+		const PrimitiveType g_allPrimitiveTypes[] =
+		{
+			{"triangles", GL_TRIANGLES},
+			{"tri-strip", GL_TRIANGLE_STRIP},
+			{"tri-fan", GL_TRIANGLE_FAN},
+			{"lines", GL_LINES},
+			{"line-strip", GL_LINE_STRIP},
+			{"line-loop", GL_LINE_LOOP},
+			{"points", GL_POINTS},
+		};
+	}
+
+	struct AttribTypeFinder
+	{
+		typedef std::string first_argument_type;
+		typedef AttribType second_argument_type;
+		typedef bool result_type;
+
+		bool operator() (const std::string &compareString, const AttribType &attrib) const
+		{
+			return compareString == attrib.strNameFromFile;
+		}
+
+	};
+
+	struct PrimitiveTypeFinder
+	{
+		typedef std::string first_argument_type;
+		typedef PrimitiveType second_argument_type;
+		typedef bool result_type;
+
+		bool operator() (const std::string &compareString, const PrimitiveType &prim) const
+		{
+			return compareString == prim.strPrimitiveName;
+		}
+
+	};
+
+	const AttribType *GetAttribType(const std::string &strType)
+	{
+		int iArrayCount = ARRAY_COUNT(g_allAttributeTypes);
+		const AttribType *pAttrib = std::find_if(
+			g_allAttributeTypes, &g_allAttributeTypes[iArrayCount], std::bind1st(AttribTypeFinder(), strType));
+
+		if(pAttrib == &g_allAttributeTypes[iArrayCount])
+			throw std::exception("Unknown 'type' field.");
+
+		return pAttrib;
+	}
+
+	struct Attribute
+	{
+		Attribute()
+			: iAttribIx(0xFFFFFFFF)
+			, pAttribType(NULL)
+			, iSize(-1)
+		{}
+
+		explicit Attribute(const TiXmlElement *pAttribElem)
+		{
+			int iAttributeIndex;
+			if(pAttribElem->QueryIntAttribute("index", &iAttributeIndex) != TIXML_SUCCESS)
+				throw std::exception("Missing 'index' attribute in an 'attribute' element.");
+			if(!((0 <= iAttributeIndex) && (iAttributeIndex < 16)))
+				throw std::exception("Attribute index must be between 0 and 16.");
+			iAttribIx = iAttributeIndex;
+
+			int iVectorSize;
+			if(pAttribElem->QueryIntAttribute("size", &iVectorSize) != TIXML_SUCCESS)
+				throw std::exception("Missing 'size' attribute in an 'attribute' element.");
+			if(!((1 <= iVectorSize) && (iVectorSize < 5)))
+				throw std::exception("Attribute size must be between 1 and 4.");
+			iSize = iVectorSize;
+
+			std::string strType;
+			if(pAttribElem->QueryStringAttribute("type", &strType) != TIXML_SUCCESS)
+				throw std::exception("Missing 'type' attribute in an 'attribute' element.");
+
+			pAttribType = GetAttribType(strType);
+		
+			//Read the text data.
+			std::stringstream strStream;
+			for(const TiXmlNode *pNode = pAttribElem->FirstChild();
+				pNode;
+				pNode = pNode->NextSibling())
+			{
+				const TiXmlText *pText = pNode->ToText();
+				if(pText)
+				{
+					strStream << pText->ValueStr() << " ";
+				}
+			}
+
+			strStream.flush();
+			const std::string &strTest = strStream.str();
+
+			//Parse the text stream.
+			pAttribType->ParseFunc(dataArray, strStream);
+			if(dataArray.empty())
+				throw std::exception("The attribute's must have an array of values.");
+			if(dataArray.size() % iSize != 0)
+				throw std::exception("The attribute's data must be a multiple of its size in elements.");
+		}
+
+		Attribute(const Attribute &rhs)
+		{
+			iAttribIx = rhs.iAttribIx;
+			pAttribType = rhs.pAttribType;
+			iSize = rhs.iSize;
+			dataArray = rhs.dataArray;
+		}
+
+		Attribute &operator=(const Attribute &rhs)
+		{
+			iAttribIx = rhs.iAttribIx;
+			pAttribType = rhs.pAttribType;
+			iSize = rhs.iSize;
+			dataArray = rhs.dataArray;
+			return *this;
+		}
+
+		size_t NumElements() const
+		{
+			return dataArray.size() / iSize;
+		}
+
+		size_t CalcByteSize() const
+		{
+			return dataArray.size() * pAttribType->iNumBytes;
+		}
+
+		void FillBoundBufferObject(size_t iOffset) const
+		{
+			pAttribType->WriteToBuffer(GL_ARRAY_BUFFER, dataArray, iSize, iOffset);
+		}
+
+		void SetupAttributeArray(size_t iOffset) const
+		{
+			glEnableVertexAttribArray(iAttribIx);
+			glVertexAttribPointer(iAttribIx,
+				iSize,
+				pAttribType->eGLType,
+				pAttribType->bNormalized ? GL_TRUE : GL_FALSE,
+				0,
+				(void*)iOffset);
+		}
+
+		GLuint iAttribIx;
+		const AttribType *pAttribType;
+		int iSize;
+		std::vector<AttribData> dataArray;
+	};
+
+	struct IndexData
+	{
+		IndexData(const TiXmlElement *pIndexElem)
+		{
+			std::string strType;
+			if(pIndexElem->QueryStringAttribute("type", &strType) != TIXML_SUCCESS)
+				throw std::exception("Missing 'type' attribute in an 'index' element.");
+
+			if(strType != "uint" && strType != "ushort" && strType != "ubyte")
+				throw std::exception("Improper 'type' attribute value on 'index' element.");
+
+			pAttribType = GetAttribType(strType);
+
+			//Read the text data.
+			std::stringstream strStream;
+			for(const TiXmlNode *pNode = pIndexElem->FirstChild();
+				pNode;
+				pNode = pNode->NextSibling())
+			{
+				const TiXmlText *pText = pNode->ToText();
+				if(pText)
+				{
+					strStream << pText->ValueStr() << " ";
+				}
+			}
+
+			strStream.flush();
+			const std::string &strTest = strStream.str();
+
+			//Parse the text stream.
+			pAttribType->ParseFunc(dataArray, strStream);
+			if(dataArray.empty())
+				throw std::exception("The index element must have an array of values.");
+		}
+
+		IndexData()
+			: pAttribType(NULL)
+		{}
+
+		IndexData(const IndexData &rhs)
+		{
+			pAttribType = rhs.pAttribType;
+			dataArray = rhs.dataArray;
+		}
+
+		IndexData &operator=(const IndexData &rhs)
+		{
+			pAttribType = rhs.pAttribType;
+			dataArray = rhs.dataArray;
+			return *this;
+		}
+
+		size_t CalcByteSize() const
+		{
+			return dataArray.size() * pAttribType->iNumBytes;
+		}
+
+		void FillBoundBufferObject(size_t iOffset) const
+		{
+			pAttribType->WriteToBuffer(GL_ELEMENT_ARRAY_BUFFER, dataArray, 1, iOffset);
+		}
+
+		const AttribType *pAttribType;
+		std::vector<AttribData> dataArray;
+	};
+
+	RenderCmd ProcessRenderCmd(const TiXmlElement *pCmdElem)
+	{
+		RenderCmd cmd;
+
+		std::string strCmdName;
+		if(pCmdElem->QueryStringAttribute("cmd", &strCmdName) != TIXML_SUCCESS)
+			throw std::exception("Missing 'cmd' attribute in an 'arrays' or 'indices' element.");
+
+		int iArrayCount = ARRAY_COUNT(g_allAttributeTypes);
+		const PrimitiveType *pPrim = std::find_if(
+			g_allPrimitiveTypes, &g_allPrimitiveTypes[iArrayCount],
+			std::bind1st(PrimitiveTypeFinder(), strCmdName));
+
+		if(pPrim == &g_allPrimitiveTypes[iArrayCount])
+			throw std::exception("Unknown 'cmd' field.");
+
+		cmd.ePrimType = pPrim->eGLPrimType;
+
+		if(pCmdElem->ValueStr() == "indices")
+		{
+			cmd.bIsIndexedCmd = true;
+			int iPrimRestart;
+			if(pCmdElem->QueryIntAttribute("prim-restart", &iPrimRestart) == TIXML_SUCCESS)
+			{
+				if(iPrimRestart < 0)
+					throw std::exception("Attribute 'start' must be between 0 or greater.");
+			}
+			else
+				iPrimRestart = -1;
+			cmd.primRestart = iPrimRestart;
+		}
+		else if(pCmdElem->ValueStr() == "arrays")
+		{
+			cmd.bIsIndexedCmd = false;
+			int iStart;
+			if(pCmdElem->QueryIntAttribute("start", &iStart) != TIXML_SUCCESS)
+				throw std::exception("Missing 'start' attribute in an 'arrays' element.");
+			if(iStart < 0)
+				throw std::exception("Attribute 'start' must be between 0 or greater.");
+			cmd.start = iStart;
+
+			int iCount;
+			if(pCmdElem->QueryIntAttribute("count", &iCount) != TIXML_SUCCESS)
+				throw std::exception("Missing 'count' attribute in an 'arrays' element.");
+			if(iCount <= 0)
+				throw std::exception("Attribute 'count' must be between 0 or greater.");
+			cmd.elemCount = iCount;
+		}
+		else
+			throw std::exception("Bad element. Must be 'indices' or 'arrays'.");
+
+		return cmd;
+	}
+
+	struct MeshData
+	{
+		MeshData()
+			: oAttribArraysBuffer(0)
+			, oIndexBuffer(0)
+			, oVAO(0)
+		{}
+
+		GLuint oAttribArraysBuffer;
+		GLuint oIndexBuffer;
+		GLuint oVAO;
+
+		std::vector<RenderCmd> primatives;
+	};
+
+	Mesh::Mesh( const std::string &strFilename )
+		: m_pData(new MeshData)
+	{
+		std::vector<Attribute> attribs;
+		attribs.reserve(16); //Max possible attributes
+
+		std::vector<IndexData> indexData;
+
+		{
+			std::string strDataFilename = "data\\" + strFilename;
+			std::ifstream fileStream(strDataFilename.c_str());
+
+			TiXmlDocument theDoc;
+
+			fileStream >> theDoc;
+			fileStream.close();
+
+			if(theDoc.Error())
+				throw std::exception(theDoc.ErrorDesc());
+
+			TiXmlHandle docHandle(&theDoc);
+
+			const TiXmlElement *pProcNode = docHandle.FirstChild("mesh").FirstChild().ToElement();
+			while(pProcNode->ValueStr() == "attribute")
+			{
+				attribs.push_back(Attribute(pProcNode));
+				pProcNode = pProcNode->NextSiblingElement();
+			}
+
+			for(; pProcNode; pProcNode = pProcNode->NextSiblingElement())
+			{
+				m_pData->primatives.push_back(ProcessRenderCmd(pProcNode));
+				if(pProcNode->ValueStr() == "indices")
+					indexData.push_back(IndexData(pProcNode));
+			}
+		}
+
+		//Figure out how big of a buffer object for the attribute data we need.
+		size_t iAttrbBufferSize = 0;
+		std::vector<size_t> attribStartLocs;
+		attribStartLocs.reserve(attribs.size());
+		int iNumElements = 0;
+		for(size_t iLoop = 0; iLoop < attribs.size(); iLoop++)
+		{
+			iAttrbBufferSize = iAttrbBufferSize % 16 ?
+				(iAttrbBufferSize + (16 - iAttrbBufferSize % 16)) : iAttrbBufferSize;
+
+			attribStartLocs.push_back(iAttrbBufferSize);
+			const Attribute &attrib = attribs[iLoop];
+
+			iAttrbBufferSize += attrib.CalcByteSize();
+
+			if(iNumElements)
+			{
+				if(iNumElements != attrib.NumElements())
+					throw std::exception("Some of the attribute arrays have different element counts.");
+			}
+			else
+				iNumElements = attrib.NumElements();
+		}
+
+		//Create our VAO.
+		glGenVertexArrays(1, &m_pData->oVAO);
+		glBindVertexArray(m_pData->oVAO);
+
+		//Create the buffer object.
+		glGenBuffers(1, &m_pData->oAttribArraysBuffer);
+		glBindBuffer(GL_ARRAY_BUFFER, m_pData->oAttribArraysBuffer);
+		glBufferData(GL_ARRAY_BUFFER, iAttrbBufferSize, NULL, GL_STATIC_DRAW);
+
+		//Fill in our data and set up the attribute arrays.
+		for(size_t iLoop = 0; iLoop < attribs.size(); iLoop++)
+		{
+			const Attribute &attrib = attribs[iLoop];
+			attrib.FillBoundBufferObject(attribStartLocs[iLoop]);
+			attrib.SetupAttributeArray(attribStartLocs[iLoop]);
+		}
+
+		//Get the size of our index buffer data.
+		size_t iIndexBufferSize = 0;
+		std::vector<size_t> indexStartLocs;
+		indexStartLocs.reserve(indexData.size());
+		for(size_t iLoop = 0; iLoop < indexData.size(); iLoop++)
+		{
+			iIndexBufferSize = iIndexBufferSize % 16 ?
+				(iIndexBufferSize + (16 - iIndexBufferSize % 16)) : iIndexBufferSize;
+
+			indexStartLocs.push_back(iIndexBufferSize);
+			const IndexData &currData = indexData[iLoop];
+
+			iIndexBufferSize += currData.CalcByteSize();
+		}
+
+		//Create the index buffer object.
+		if(iIndexBufferSize)
+		{
+			glGenBuffers(1, &m_pData->oIndexBuffer);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pData->oIndexBuffer);
+			glBufferData(GL_ELEMENT_ARRAY_BUFFER, iIndexBufferSize, NULL, GL_STATIC_DRAW);
+
+			//Fill with data.
+			for(size_t iLoop = 0; iLoop < indexData.size(); iLoop++)
+			{
+				const IndexData &currData = indexData[iLoop];
+				currData.FillBoundBufferObject(indexStartLocs[iLoop]);
+			}
+
+			//Fill in indexed rendering commands.
+			size_t iCurrIndexed = 0;
+			for(size_t iLoop = 0; iLoop < m_pData->primatives.size(); iLoop++)
+			{
+				RenderCmd &prim = m_pData->primatives[iLoop];
+				if(prim.bIsIndexedCmd)
+				{
+					prim.start = (GLuint)indexStartLocs[iCurrIndexed];
+					prim.elemCount = (GLuint)indexData[iCurrIndexed].dataArray.size();
+				}
+			}
+		}
+
+		glBindVertexArray(0);
+	}
+
+	Mesh::~Mesh()
+	{
+		delete m_pData;
+	}
+
+	void Mesh::Render()
+	{
+		if(!m_pData->oVAO)
+			return;
+
+		glBindVertexArray(m_pData->oVAO);
+		std::for_each(m_pData->primatives.begin(), m_pData->primatives.end(),
+			std::mem_fun_ref(&RenderCmd::Render));
+		glBindVertexArray(0);
+	}
+
+	void Mesh::DeleteObjects()
+	{
+		glDeleteBuffers(1, &m_pData->oAttribArraysBuffer);
+		m_pData->oAttribArraysBuffer = 0;
+		glDeleteBuffers(1, &m_pData->oIndexBuffer);
+		m_pData->oIndexBuffer = 0;
+		glDeleteVertexArrays(1, &m_pData->oVAO);
+		m_pData->oVAO = 0;
+	}
+
 	namespace
 	{
 		inline float DegToRad(float fAngDeg)

framework/framework.h

 #define FRAMEWORK_H
 
 #include <stack>
+#include <string>
 #include <glm/glm.hpp>
 
 namespace Framework
 	GLuint LoadShader(GLenum eShaderType, const std::string &strShaderFilename);
 	GLuint CreateProgram(const std::vector<GLuint> &shaderList);
 
+	struct MeshData;
+
+	class Mesh
+	{
+	public:
+		Mesh(const std::string &strFilename);
+		~Mesh();
+
+		void Render();
+		void DeleteObjects();
+
+	private:
+		MeshData *m_pData;
+	};
+
 	class MatrixStack
 	{
+	public:
 		MatrixStack()
 			: m_currMat(1.0f)
 		{