# Commits

committed 59e68e9

• Participants
• Parent commits c1d2a92
• Branches default

# File 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>`

# File 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>`

# File Test/data/mesh.xml

`+<?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>`

# File Test/test.cpp

` `
`-#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;`
`-	}`
`-}`

# File 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)`

# File 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)`
` 		{`