Commits

Jason McKesson committed c1e3d3f

First Phong tutorial code finished.

  • Participants
  • Parent commits 1efa9f6

Comments (0)

Files changed (17)

Tut 10 Shinies/Phong Lighting.cpp

+#include <string>
+#include <vector>
+#include <stack>
+#include <math.h>
+#include <glloader/gl_3_2_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.h"
+#include "../framework/Mesh.h"
+#include "../framework/MatrixStack.h"
+#include "../framework/MousePole.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
+struct ProgramData
+{
+	GLuint theProgram;
+
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+
+	GLuint lightIntensityUnif;
+	GLuint ambientIntensityUnif;
+
+	GLuint normalModelToCameraMatrixUnif;
+	GLuint cameraSpaceLightPosUnif;
+	GLuint clipToCameraMatrixUnif;
+	GLuint windowSizeUnif;
+	GLuint depthRangeUnif;
+	GLuint lightAttenuationUnif;
+	GLuint shininessFactorUnif;
+};
+
+struct UnlitProgData
+{
+	GLuint theProgram;
+
+	GLuint objectColorUnif;
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+ProgramData g_WhiteNoPhong;
+ProgramData g_ColorNoPhong;
+
+ProgramData g_WhitePhong;
+ProgramData g_ColorPhong;
+
+ProgramData g_WhitePhongOnly;
+ProgramData g_ColorPhongOnly;
+
+UnlitProgData g_Unlit;
+
+UnlitProgData LoadUnlitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
+
+	UnlitProgData data;
+	data.theProgram = Framework::CreateProgram(shaderList);
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
+	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
+	data.objectColorUnif = glGetUniformLocation(data.theProgram, "objectColor");
+
+	return data;
+}
+
+ProgramData LoadLitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
+
+	ProgramData data;
+	data.theProgram = Framework::CreateProgram(shaderList);
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
+	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
+	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
+	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
+
+	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
+	data.cameraSpaceLightPosUnif = glGetUniformLocation(data.theProgram, "cameraSpaceLightPos");
+	data.clipToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "clipToCameraMatrix");
+	data.windowSizeUnif = glGetUniformLocation(data.theProgram, "windowSize");
+	data.depthRangeUnif = glGetUniformLocation(data.theProgram, "depthRange");
+	data.lightAttenuationUnif = glGetUniformLocation(data.theProgram, "lightAttenuation");
+	data.shininessFactorUnif = glGetUniformLocation(data.theProgram, "shininessFactor");
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	g_WhiteNoPhong = LoadLitProgram("PN.vert", "NoPhong.frag");
+	g_ColorNoPhong = LoadLitProgram("PCN.vert", "NoPhong.frag");
+
+	g_WhitePhong = LoadLitProgram("PN.vert", "PhongLighting.frag");
+	g_ColorPhong = LoadLitProgram("PCN.vert", "PhongLighting.frag");
+
+	g_WhitePhongOnly = LoadLitProgram("PN.vert", "PhongOnly.frag");
+	g_ColorPhongOnly = LoadLitProgram("PCN.vert", "PhongOnly.frag");
+
+	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
+}
+
+Framework::Mesh *g_pCylinderMesh = NULL;
+Framework::Mesh *g_pPlaneMesh = NULL;
+Framework::Mesh *g_pCubeMesh = NULL;
+
+Framework::RadiusDef radiusDef = {5.0f, 3.0f, 200.0f, 1.5f, 0.5f};
+Framework::MousePole g_mousePole(glm::vec3(0.0f, 0.5f, 0.0f), radiusDef);
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseButton(int button, int state, int x, int y)
+	{
+		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseWheel(int wheel, int direction, int x, int y)
+	{
+		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+}
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializePrograms();
+
+	try
+	{
+		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
+		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
+		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+ 	glutMouseFunc(MouseButton);
+ 	glutMotionFunc(MouseMotion);
+	glutMouseWheelFunc(MouseWheel);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	const float depthZNear = 0.0f;
+	const float depthZFar = 1.0f;
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(GL_TRUE);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(depthZNear, depthZFar);
+	glEnable(GL_DEPTH_CLAMP);
+
+	glUseProgram(g_WhiteNoPhong.theProgram);
+	glUniform2f(g_WhiteNoPhong.depthRangeUnif,depthZNear, depthZFar);
+	glUseProgram(g_WhitePhong.theProgram);
+	glUniform2f(g_WhitePhong.depthRangeUnif,depthZNear, depthZFar);
+	glUseProgram(g_WhitePhongOnly.theProgram);
+	glUniform2f(g_WhitePhongOnly.depthRangeUnif,depthZNear, depthZFar);
+
+	glUseProgram(g_ColorNoPhong.theProgram);
+	glUniform2f(g_ColorNoPhong.depthRangeUnif,depthZNear, depthZFar);
+	glUseProgram(g_ColorPhong.theProgram);
+	glUniform2f(g_ColorPhong.depthRangeUnif,depthZNear, depthZFar);
+	glUseProgram(g_ColorPhongOnly.theProgram);
+	glUniform2f(g_ColorPhongOnly.depthRangeUnif,depthZNear, depthZFar);
+	glUseProgram(0);
+}
+
+static float g_fLightHeight = 1.5f;
+static float g_fLightRadius = 1.0f;
+static bool g_bRotateLight = true;
+
+static float g_fRotateTime = 0.0f;
+static float g_fPrevTime = 0.0f;
+
+glm::vec4 CalcLightPosition()
+{
+	const float fLoopDuration = 5.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fCurrTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
+	float fDeltaTime = fCurrTime - g_fPrevTime;
+	g_fPrevTime = fCurrTime;
+
+	if(g_bRotateLight)
+		g_fRotateTime += fDeltaTime;
+
+	float fCurrTimeThroughLoop = fmodf(g_fRotateTime, fLoopDuration);
+
+	glm::vec4 ret(0.0f, g_fLightHeight, 0.0f, 1.0f);
+
+	ret.x = cosf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
+	ret.z = sinf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
+
+	return ret;
+}
+
+static float g_CylYaw = 0.0f;
+static float g_CylPitch = 0.0f;
+static float g_CylRoll = 0.0f;
+
+enum LightingModel
+{
+	LM_PURE_DIFFUSE = 0,
+	LM_DIFFUSE_AND_SPECULAR,
+	LM_SPECULAR_ONLY,
+
+	LM_MAX_LIGHTING_MODEL,
+};
+
+static int g_eLightModel = LM_DIFFUSE_AND_SPECULAR;
+
+static bool g_bUseFragmentLighting = true;
+static bool g_bDrawColoredCyl = false;
+static bool g_bDrawLight = false;
+static bool g_bScaleCyl = false;
+
+const float g_fLightAttenuation = 1.2f;
+static float g_fShininessFactor = 4.0f;
+
+//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);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	if(g_pPlaneMesh && g_pCylinderMesh && g_pCubeMesh)
+	{
+		Framework::MatrixStack modelMatrix;
+		modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
+
+		const glm::vec4 &worldLightPos = CalcLightPosition();
+		const glm::vec4 &lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
+
+		ProgramData *pWhiteProg = NULL;
+		ProgramData *pColorProg = NULL;
+
+		switch(g_eLightModel)
+		{
+		case LM_PURE_DIFFUSE:
+			pWhiteProg = &g_WhiteNoPhong;
+			pColorProg = &g_ColorNoPhong;
+			break;
+		case LM_DIFFUSE_AND_SPECULAR:
+			pWhiteProg = &g_WhitePhong;
+			pColorProg = &g_ColorPhong;
+			break;
+		case LM_SPECULAR_ONLY:
+			pWhiteProg = &g_WhitePhongOnly;
+			pColorProg = &g_ColorPhongOnly;
+			break;
+		}
+
+		glUseProgram(pWhiteProg->theProgram);
+		glUniform4f(pWhiteProg->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
+		glUniform4f(pWhiteProg->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
+		glUniform3fv(pWhiteProg->cameraSpaceLightPosUnif,1, glm::value_ptr(lightPosCameraSpace));
+		glUniform1f(pWhiteProg->lightAttenuationUnif, g_fLightAttenuation);
+		glUniform1f(pWhiteProg->shininessFactorUnif, g_fShininessFactor);
+
+		glUseProgram(pColorProg->theProgram);
+		glUniform4f(pColorProg->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
+		glUniform4f(pColorProg->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
+		glUniform3fv(pColorProg->cameraSpaceLightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
+		glUniform1f(pColorProg->lightAttenuationUnif, g_fLightAttenuation);
+		glUniform1f(pColorProg->shininessFactorUnif, g_fShininessFactor);
+		glUseProgram(0);
+
+		{
+			Framework::MatrixStackPusher push(modelMatrix);
+
+			//Render the ground plane.
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				glm::mat3 normMatrix(modelMatrix.Top());
+				normMatrix = glm::transpose(glm::inverse(normMatrix));
+
+				glUseProgram(pWhiteProg->theProgram);
+				glUniformMatrix4fv(pWhiteProg->modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+
+				glUniformMatrix3fv(pWhiteProg->normalModelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(normMatrix));
+				g_pPlaneMesh->Render();
+				glUseProgram(0);
+			}
+
+			//Render the Cylinder
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				modelMatrix.Translate(0.0f, 0.5f, 0.0f);
+
+				modelMatrix.RotateX(g_CylPitch);
+				modelMatrix.RotateY(g_CylYaw);
+				modelMatrix.RotateZ(g_CylRoll);
+
+				if(g_bScaleCyl)
+					modelMatrix.Scale(1.0f, 1.0f, 0.2f);
+
+				glm::mat3 normMatrix(modelMatrix.Top());
+				normMatrix = glm::transpose(glm::inverse(normMatrix));
+
+				ProgramData *pProg = g_bDrawColoredCyl ? pColorProg : pWhiteProg;
+				glUseProgram(pProg->theProgram);
+				glUniformMatrix4fv(pProg->modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+
+				glUniformMatrix3fv(pProg->normalModelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(normMatrix));
+
+				if(g_bDrawColoredCyl)
+					g_pCylinderMesh->Render("tint");
+				else
+					g_pCylinderMesh->Render("flat");
+
+				glUseProgram(0);
+			}
+
+			//Render the light
+			if(g_bDrawLight)
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				modelMatrix.Translate(glm::vec3(worldLightPos));
+				modelMatrix.Scale(0.1f, 0.1f, 0.1f);
+
+				glUseProgram(g_Unlit.theProgram);
+				glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+				glUniform4f(g_Unlit.objectColorUnif, 0.8078f, 0.8706f, 0.9922f, 1.0f);
+				g_pCubeMesh->Render("flat");
+			}
+		}
+	}
+
+	glutPostRedisplay();
+	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)
+{
+	Framework::MatrixStack persMatrix;
+	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
+	const glm::mat4 &invMat = glm::inverse(persMatrix.Top());
+
+	glUseProgram(g_WhiteNoPhong.theProgram);
+	glUniformMatrix4fv(g_WhiteNoPhong.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_WhiteNoPhong.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_WhiteNoPhong.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_ColorNoPhong.theProgram);
+	glUniformMatrix4fv(g_ColorNoPhong.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_ColorNoPhong.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_ColorNoPhong.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_WhitePhong.theProgram);
+	glUniformMatrix4fv(g_WhitePhong.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_WhitePhong.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_WhitePhong.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_ColorPhong.theProgram);
+	glUniformMatrix4fv(g_ColorPhong.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_ColorPhong.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_ColorPhong.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_WhitePhongOnly.theProgram);
+	glUniformMatrix4fv(g_WhitePhongOnly.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_WhitePhongOnly.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_WhitePhongOnly.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_ColorPhongOnly.theProgram);
+	glUniformMatrix4fv(g_ColorPhongOnly.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUniform2i(g_ColorPhongOnly.windowSizeUnif, w, h);
+	glUniformMatrix4fv(g_ColorPhongOnly.clipToCameraMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(invMat));
+
+	glUseProgram(g_Unlit.theProgram);
+	glUniformMatrix4fv(g_Unlit.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(0);
+
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+	glutPostRedisplay();
+}
+
+static const char *strLightModelNames[] =
+{
+	"Diffuse only.",
+	"Specular + diffuse.",
+	"Specular only.",
+};
+
+
+//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)
+{
+	bool bChangedShininess = false;
+	bool bChangedLightModel = false;
+	switch (key)
+	{
+	case 27:
+		delete g_pPlaneMesh;
+		delete g_pCylinderMesh;
+		delete g_pCubeMesh;
+		glutLeaveMainLoop();
+		break;
+	case 'w': g_CylPitch -= 11.25f; break;
+	case 's': g_CylPitch += 11.25f; break;
+	case 'd': g_CylRoll -= 11.25f; break;
+	case 'a': g_CylRoll += 11.25f; break;
+	case 'e': g_CylYaw -= 11.25f; break;
+	case 'q': g_CylYaw += 11.25f; break;
+	case 'W': g_CylPitch -= 4.0f; break;
+	case 'S': g_CylPitch += 4.0f; break;
+	case 'D': g_CylRoll -= 4.0f; break;
+	case 'A': g_CylRoll += 4.0f; break;
+	case 'E': g_CylYaw -= 4.0f; break;
+	case 'Q': g_CylYaw += 4.0f; break;
+		
+	case 32:
+		g_bDrawColoredCyl = !g_bDrawColoredCyl;
+		printf("Yaw: %f, Pitch: %f, Roll: %f\n", g_CylYaw, g_CylPitch, g_CylRoll);
+		break;
+
+	case 'i': g_fLightHeight += 0.2f; break;
+	case 'k': g_fLightHeight -= 0.2f; break;
+	case 'l': g_fLightRadius += 0.2f; break;
+	case 'j': g_fLightRadius -= 0.2f; break;
+	case 'I': g_fLightHeight += 0.05f; break;
+	case 'K': g_fLightHeight -= 0.05f; break;
+	case 'L': g_fLightRadius += 0.05f; break;
+	case 'J': g_fLightRadius -= 0.05f; break;
+
+	case 'o': g_fShininessFactor += 0.5f; bChangedShininess = true; break;
+	case 'u': g_fShininessFactor -= 0.5f; bChangedShininess = true; break;
+
+	case 'y': g_bDrawLight = !g_bDrawLight; break;
+	case 't': g_bScaleCyl = !g_bScaleCyl; break;
+	case 'b': g_bRotateLight = !g_bRotateLight; break;
+	case 'h':
+		g_eLightModel += 1;
+		g_eLightModel %= LM_MAX_LIGHTING_MODEL;
+		bChangedLightModel = true;
+		break;
+	case 'H':
+		switch(g_eLightModel)
+		{
+		case LM_DIFFUSE_AND_SPECULAR:
+			g_eLightModel = LM_PURE_DIFFUSE;
+			break;
+		case LM_PURE_DIFFUSE:
+			g_eLightModel = LM_DIFFUSE_AND_SPECULAR;
+			break;
+		case LM_SPECULAR_ONLY:
+			g_eLightModel = LM_PURE_DIFFUSE;
+			break;
+		}
+		bChangedLightModel = true;
+		break;
+	}
+
+	if(g_fLightRadius < 0.2f)
+		g_fLightRadius = 0.2f;
+
+	if(g_fShininessFactor < 1.0f)
+		g_fShininessFactor = 1.0f;
+
+	if(bChangedShininess)
+		printf("Shiny: %f\n", g_fShininessFactor);
+
+	if(bChangedLightModel)
+		printf("%s\n", strLightModelNames[g_eLightModel]);
+
+	glutPostRedisplay();
+}
+
+

Tut 10 Shinies/data/GenCube.lua

+require "XmlWriter"
+require "vmath"
+
+local function GenStringFromArray(theArray, bAsInt)
+	local array = {" "}
+	for i, vector in ipairs(theArray) do
+		local elements = vector;
+		if(bAsInt) then
+			elements = {};
+			for i, value in ipairs(vector) do
+				elements[#elements + 1] = string.format("%i", value);
+			end
+		end
+		
+		array[#array + 1] = "        " .. table.concat(vector, " ");
+	end
+	
+	return table.concat(array, "\n");
+end
+
+local positions =
+{
+	--Front
+	vmath.vec3( 0.5,  0.5,  0.5),
+	vmath.vec3( 0.5, -0.5,  0.5),
+	vmath.vec3(-0.5, -0.5,  0.5),
+	vmath.vec3(-0.5,  0.5,  0.5),
+
+	--Top
+	vmath.vec3( 0.5,  0.5,  0.5),
+	vmath.vec3(-0.5,  0.5,  0.5),
+	vmath.vec3(-0.5,  0.5, -0.5),
+	vmath.vec3( 0.5,  0.5, -0.5),
+
+	--Left
+	vmath.vec3( 0.5,  0.5,  0.5),
+	vmath.vec3( 0.5,  0.5, -0.5),
+	vmath.vec3( 0.5, -0.5, -0.5),
+	vmath.vec3( 0.5, -0.5,  0.5),
+
+	--Back
+	vmath.vec3( 0.5,  0.5, -0.5),
+	vmath.vec3(-0.5,  0.5, -0.5),
+	vmath.vec3(-0.5, -0.5, -0.5),
+	vmath.vec3( 0.5, -0.5, -0.5),
+
+	--Bottom
+	vmath.vec3( 0.5, -0.5,  0.5),
+	vmath.vec3( 0.5, -0.5, -0.5),
+	vmath.vec3(-0.5, -0.5, -0.5),
+	vmath.vec3(-0.5, -0.5,  0.5),
+
+	--Right
+	vmath.vec3(-0.5,  0.5,  0.5),
+	vmath.vec3(-0.5, -0.5,  0.5),
+	vmath.vec3(-0.5, -0.5, -0.5),
+	vmath.vec3(-0.5,  0.5, -0.5),
+};
+
+local tints =
+{
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+	vmath.vec4(1.0, 1.0, 1.0, 1.0),
+
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+	vmath.vec4(0.75, 0.75, 0.75, 1.0),
+
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+	vmath.vec4(0.5, 0.5, 0.5, 1.0),
+}
+
+local colors =
+{
+	vmath.vec4(0.0, 1.0, 0.0, 1.0),
+	vmath.vec4(0.0, 1.0, 0.0, 1.0),
+	vmath.vec4(0.0, 1.0, 0.0, 1.0),
+	vmath.vec4(0.0, 1.0, 0.0, 1.0),
+
+	vmath.vec4(0.0, 0.0, 1.0, 1.0),
+	vmath.vec4(0.0, 0.0, 1.0, 1.0),
+	vmath.vec4(0.0, 0.0, 1.0, 1.0),
+	vmath.vec4(0.0, 0.0, 1.0, 1.0),
+
+	vmath.vec4(1.0, 0.0, 0.0, 1.0),
+	vmath.vec4(1.0, 0.0, 0.0, 1.0),
+	vmath.vec4(1.0, 0.0, 0.0, 1.0),
+	vmath.vec4(1.0, 0.0, 0.0, 1.0),
+
+	vmath.vec4(1.0, 1.0, 0.0, 1.0),
+	vmath.vec4(1.0, 1.0, 0.0, 1.0),
+	vmath.vec4(1.0, 1.0, 0.0, 1.0),
+	vmath.vec4(1.0, 1.0, 0.0, 1.0),
+
+	vmath.vec4(0.0, 1.0, 1.0, 1.0),
+	vmath.vec4(0.0, 1.0, 1.0, 1.0),
+	vmath.vec4(0.0, 1.0, 1.0, 1.0),
+	vmath.vec4(0.0, 1.0, 1.0, 1.0),
+
+	vmath.vec4(1.0, 0.0, 1.0, 1.0),
+	vmath.vec4(1.0, 0.0, 1.0, 1.0),
+	vmath.vec4(1.0, 0.0, 1.0, 1.0),
+	vmath.vec4(1.0, 0.0, 1.0, 1.0),
+}
+
+local indices =
+{
+	vmath.vec3(0, 1, 2),
+	vmath.vec3(2, 3, 0),
+
+	vmath.vec3(4, 5, 6),
+	vmath.vec3(6, 7, 4),
+
+	vmath.vec3(8, 9, 10),
+	vmath.vec3(10, 11, 8),
+
+	vmath.vec3(12, 13, 14),
+	vmath.vec3(14, 15, 12),
+
+	vmath.vec3(16, 17, 18),
+	vmath.vec3(18, 19, 16),
+
+	vmath.vec3(20, 21, 22),
+	vmath.vec3(22, 23, 20),
+};
+
+do
+	local writer = XmlWriter.XmlWriter("UnitCube.xml");
+	writer:AddPI("oxygen", [[RNGSchema="../../Documents/meshFormat.rnc" type="compact"]]);
+	writer:PushElement("mesh", "http://www.arcsynthesis.com/gltut/mesh");
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "0");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(positions));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "1");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "4");
+			writer:AddText(GenStringFromArray(colors));
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "color");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "flat");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "triangles");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(GenStringFromArray(indices, true));
+		writer:PopElement();
+	writer:PopElement();
+	writer:Close();
+end

Tut 10 Shinies/data/GenCylinder.lua

+require "XmlWriter"
+require "vmath"
+
+local function GenStringFromArray(theArray)
+	local array = {" "}
+	for i, vector in ipairs(theArray) do
+		array[#array + 1] = "        " .. table.concat(vector, " ");
+	end
+	
+	return table.concat(array, "\n");
+end
+
+local positions = {};
+local colors = {};
+local normals = {};
+local topFan = {};
+local botFan = {};
+local cylStrip = {};
+
+local iSegCount, iColorRepeatCount = ...;
+iSegCount = iSegCount or 30;
+iColorRepeatCount = iColorRepeatCount or 3;
+
+local iAngle = 3.14159 * 2.0 / iSegCount;
+local iColorCycleAngle = 3.14159 * 2.0 / iColorRepeatCount;
+local highColor = vmath.vec4(0.9, 0.5, 0.5, 1.0);
+local lowColor = vmath.vec4(0.5, 0.1, 0.1, 1.0)
+
+--Compute caps
+positions[#positions + 1] = vmath.vec3(0.0, 0.5, 0.0);
+colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+normals[#normals + 1] = vmath.vec3(0.0, 1.0, 0.0);
+topFan[#topFan + 1] = 0;
+botFan[#botFan + 1] = (iSegCount * 2) + 1;
+
+local firstSideIx = #positions;
+
+for iSeg = 0, (iSegCount - 1), 1 do
+	local iCurrAngle = iSeg * iAngle;
+
+	positions[#positions + 1] =
+		vmath.vec3(0.5 * math.cos(iCurrAngle), 0.5, 0.5 * math.sin(iCurrAngle));
+	positions[#positions + 1] =
+		vmath.vec3(0.5 * math.cos(iCurrAngle), -0.5, 0.5 * math.sin(iCurrAngle));
+
+	normals[#normals + 1] = vmath.vec3(0.0, 1.0, 0.0);
+	normals[#normals + 1] = vmath.vec3(0.0, -1.0, 0.0);
+		
+	local clrDist = math.mod(iCurrAngle, iColorCycleAngle) / iColorCycleAngle;
+	if(clrDist > 0.5) then
+		local interp = (clrDist - 0.5) * 2;
+		colors[#colors + 1] = (interp * highColor) +
+			((1 - interp) * lowColor);
+	else
+		local interp = clrDist * 2;
+		colors[#colors + 1] = (interp * lowColor) +
+			((1 - interp) * highColor);
+	end
+	
+	colors[#colors + 1] = colors[#colors];
+
+	topFan[#topFan + 1] = 1 + (iSeg * 2);
+	botFan[#botFan + 1] = 1 + (((iSegCount - iSeg) * 2) - 1);
+end
+
+topFan[#topFan + 1] = topFan[2];
+botFan[#botFan + 1] = botFan[2];
+
+positions[#positions + 1] = vmath.vec3(0.0, -0.5, 0.0);
+colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+normals[#normals + 1] = vmath.vec3(0.0, -1.0, 0.0);
+
+--Compute sides.
+for iSeg = 0, (iSegCount - 1), 1 do
+	local iCurrAngle = iSeg * iAngle;
+
+	positions[#positions + 1] =
+		vmath.vec3(0.5 * math.cos(iCurrAngle), 0.5, 0.5 * math.sin(iCurrAngle));
+	positions[#positions + 1] =
+		vmath.vec3(0.5 * math.cos(iCurrAngle), -0.5, 0.5 * math.sin(iCurrAngle));
+
+	normals[#normals + 1] = vmath.vec3(math.cos(iCurrAngle), 0, math.sin(iCurrAngle));
+	normals[#normals + 1] = normals[#normals];
+		
+	local clrDist = math.mod(iCurrAngle, iColorCycleAngle) / iColorCycleAngle;
+	if(clrDist > 0.5) then
+		local interp = (clrDist - 0.5) * 2;
+		colors[#colors + 1] = (interp * highColor) +
+			((1 - interp) * lowColor);
+	else
+		local interp = clrDist * 2;
+		colors[#colors + 1] = (interp * lowColor) +
+			((1 - interp) * highColor);
+	end
+	
+	colors[#colors + 1] = colors[#colors];
+
+	cylStrip[#cylStrip + 1] = #positions - 2;
+	cylStrip[#cylStrip + 1] = #positions - 1;
+end
+
+cylStrip[#cylStrip + 1] = cylStrip[1];
+cylStrip[#cylStrip + 1] = cylStrip[2];
+
+do
+	local writer = XmlWriter.XmlWriter("UnitCylinder.xml");
+	writer:AddPI("oxygen", [[RNGSchema="../../Documents/meshFormat.rnc" type="compact"]]);
+	writer:PushElement("mesh", "http://www.arcsynthesis.com/gltut/mesh");
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "0");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(positions));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "1");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "4");
+			writer:AddText(GenStringFromArray(colors));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "2");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(normals));
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "tint");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "flat");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "tint-unlit");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "tri-fan");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(table.concat(topFan, " "));
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "tri-fan");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(table.concat(botFan, " "));
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "tri-strip");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(table.concat(cylStrip, " "));
+		writer:PopElement();
+	writer:PopElement();
+	writer:Close();
+end

Tut 10 Shinies/data/GenPlane.lua

+require "XmlWriter"
+require "vmath"
+
+local function GenStringFromArray(theArray, bAsInt)
+	local array = {" "}
+	for i, vector in ipairs(theArray) do
+		local elements = vector;
+		if(bAsInt) then
+			elements = {};
+			for i, value in ipairs(vector) do
+				elements[#elements + 1] = string.format("%i", value);
+			end
+		end
+		
+		array[#array + 1] = "        " .. table.concat(vector, " ");
+	end
+	
+	return table.concat(array, "\n");
+end
+
+local positions =
+{
+	vmath.vec3(0.5, 0.0, -0.5),
+	vmath.vec3(0.5, 0.0, 0.5),
+	vmath.vec3(-0.5, 0.0, 0.5),
+	vmath.vec3(-0.5, 0.0, -0.5),
+
+	vmath.vec3(0.5, 0.0, -0.5),
+	vmath.vec3(0.5, 0.0, 0.5),
+	vmath.vec3(-0.5, 0.0, 0.5),
+	vmath.vec3(-0.5, 0.0, -0.5),
+};
+
+local largePositions =
+{
+	vmath.vec3(30.0, 0.0, -30.0),
+	vmath.vec3(30.0, 0.0, 30.0),
+	vmath.vec3(-30.0, 0.0, 30.0),
+	vmath.vec3(-30.0, 0.0, -30.0),
+
+	vmath.vec3(30.0, 0.0, -30.0),
+	vmath.vec3(30.0, 0.0, 30.0),
+	vmath.vec3(-30.0, 0.0, 30.0),
+	vmath.vec3(-30.0, 0.0, -30.0),
+};
+
+local normals =
+{
+	vmath.vec3(0.0, 1.0, 0.0),
+	vmath.vec3(0.0, 1.0, 0.0),
+	vmath.vec3(0.0, 1.0, 0.0),
+	vmath.vec3(0.0, 1.0, 0.0),
+
+	vmath.vec3(0.0, -1.0, 0.0),
+	vmath.vec3(0.0, -1.0, 0.0),
+	vmath.vec3(0.0, -1.0, 0.0),
+	vmath.vec3(0.0, -1.0, 0.0),
+};
+
+local indices =
+{
+	vmath.vec3(0, 1, 2),
+	vmath.vec3(2, 3, 0),
+
+	vmath.vec3(4, 6, 5),
+	vmath.vec3(6, 4, 7),
+};
+
+do
+	local writer = XmlWriter.XmlWriter("UnitPlane.xml");
+	writer:AddPI("oxygen", [[RNGSchema="../../Documents/meshFormat.rnc" type="compact"]]);
+	writer:PushElement("mesh", "http://www.arcsynthesis.com/gltut/mesh");
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "0");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(positions));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "2");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(normals));
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "triangles");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(GenStringFromArray(indices, true));
+		writer:PopElement();
+	writer:PopElement();
+	writer:Close();
+end
+
+do
+	local writer = XmlWriter.XmlWriter("LargePlane.xml");
+	writer:AddPI("oxygen", [[RNGSchema="../../Documents/meshFormat.rnc" type="compact"]]);
+	writer:PushElement("mesh", "http://www.arcsynthesis.com/gltut/mesh");
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "0");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(largePositions));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "2");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(normals));
+		writer:PopElement();
+		writer:PushElement("indices");
+			writer:AddAttribute("cmd", "triangles");
+			writer:AddAttribute("type", "ushort");
+			writer:AddText(GenStringFromArray(indices, true));
+		writer:PopElement();
+	writer:PopElement();
+	writer:Close();
+end

Tut 10 Shinies/data/LargePlane.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="3" > 
+        30 0 -30
+        30 0 30
+        -30 0 30
+        -30 0 -30
+        30 0 -30
+        30 0 30
+        -30 0 30
+        -30 0 -30</attribute>
+	<attribute index="2" type="float" size="3" > 
+        0 1 0
+        0 1 0
+        0 1 0
+        0 1 0
+        0 -1 0
+        0 -1 0
+        0 -1 0
+        0 -1 0</attribute>
+	<indices cmd="triangles" type="ushort" > 
+        0 1 2
+        2 3 0
+        4 6 5
+        6 4 7</indices>
+</mesh>

Tut 10 Shinies/data/NoPhong.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform mat4 clipToCameraMatrix;
+uniform ivec2 windowSize;
+uniform vec2 depthRange;
+
+uniform float lightAttenuation;
+
+vec3 CalcCameraSpacePosition()
+{
+	vec3 ndcPos;
+	ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;
+	ndcPos.z = 2.0 * (gl_FragCoord.z - depthRange.x - depthRange.y) / (depthRange.y - depthRange.x);
+	
+	vec4 clipPos;
+	clipPos.w = 1.0f / gl_FragCoord.w;
+	clipPos.xyz = ndcPos.xyz * clipPos.w;
+	
+	return vec3(clipToCameraMatrix * clipPos);
+}
+
+vec4 ApplyLightIntensity(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return lightIntensity * (1 / ( 1.0 + lightAttenuation * sqrt(lightDistanceSqr)));
+}
+
+void main()
+{
+	vec3 cameraSpacePosition = CalcCameraSpacePosition();
+
+	vec3 lightDir = vec3(0.0);
+	vec4 attenIntensity = ApplyLightIntensity(cameraSpacePosition, lightDir);
+
+	float cosAngIncidence = dot(normalize(vertexNormal), lightDir);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+		(diffuseColor * ambientIntensity);
+}

Tut 10 Shinies/data/PCN.vert

+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 inDiffuseColor;
+layout(location = 2) in vec3 normal;
+
+out vec4 diffuseColor;
+out vec3 vertexNormal;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+uniform mat3 normalModelToCameraMatrix;
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
+
+	vertexNormal = normalModelToCameraMatrix * normal;
+	diffuseColor = inDiffuseColor;
+}

Tut 10 Shinies/data/PN.vert

+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 2) in vec3 normal;
+
+out vec4 diffuseColor;
+out vec3 vertexNormal;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+uniform mat3 normalModelToCameraMatrix;
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
+
+	vertexNormal = normalModelToCameraMatrix * normal;
+	diffuseColor = vec4(1.0);
+}

Tut 10 Shinies/data/PhongLighting.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+const vec4 phongIntensity = vec4(0.25, 0.25, 0.25, 1.0);
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform mat4 clipToCameraMatrix;
+uniform ivec2 windowSize;
+uniform vec2 depthRange;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(1.0);
+uniform float shininessFactor;
+
+
+vec3 CalcCameraSpacePosition()
+{
+	vec3 ndcPos;
+	ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;
+	ndcPos.z = 2.0 * (gl_FragCoord.z - depthRange.x - depthRange.y) / (depthRange.y - depthRange.x);
+	
+	vec4 clipPos;
+	clipPos.w = 1.0f / gl_FragCoord.w;
+	clipPos.xyz = ndcPos.xyz * clipPos.w;
+	
+	return vec3(clipToCameraMatrix * clipPos);
+}
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + lightAttenuation * sqrt(lightDistanceSqr)));
+}
+
+void main()
+{
+	vec3 cameraSpacePosition = CalcCameraSpacePosition();
+
+	vec3 lightDir = vec3(0.0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	vec4 phongAttenIntensity = atten * phongIntensity;
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+	float phongTerm = dot(viewDirection, reflectDir);
+	phongTerm = clamp(phongTerm, 0, 1);
+	phongTerm = dot(reflectDir, surfaceNormal) > 0.0 ? phongTerm : 0.0;
+	phongTerm = pow(phongTerm, shininessFactor);
+	
+
+	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+		(specularColor * phongAttenIntensity * phongTerm) +
+		(diffuseColor * ambientIntensity);
+}

Tut 10 Shinies/data/PhongOnly.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+const vec4 phongIntensity = vec4(0.25, 0.25, 0.25, 1.0);
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform mat4 clipToCameraMatrix;
+uniform ivec2 windowSize;
+uniform vec2 depthRange;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(1.0);
+uniform float shininessFactor;
+
+
+vec3 CalcCameraSpacePosition()
+{
+	vec3 ndcPos;
+	ndcPos.xy = ((gl_FragCoord.xy / windowSize.xy) * 2.0) - 1.0;
+	ndcPos.z = 2.0 * (gl_FragCoord.z - depthRange.x - depthRange.y) / (depthRange.y - depthRange.x);
+	
+	vec4 clipPos;
+	clipPos.w = 1.0f / gl_FragCoord.w;
+	clipPos.xyz = ndcPos.xyz * clipPos.w;
+	
+	return vec3(clipToCameraMatrix * clipPos);
+}
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + lightAttenuation * sqrt(lightDistanceSqr)));
+}
+
+void main()
+{
+	vec3 cameraSpacePosition = CalcCameraSpacePosition();
+
+	vec3 lightDir = vec3(0.0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	
+	vec4 phongAttenIntensity = atten * phongIntensity;
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+	float phongTerm = dot(viewDirection, reflectDir);
+	phongTerm = clamp(phongTerm, 0, 1);
+	phongTerm = dot(reflectDir, surfaceNormal) > 0.0 ? phongTerm : 0.0;
+	phongTerm = pow(phongTerm, shininessFactor);
+
+	outputColor = (specularColor * phongAttenIntensity * phongTerm) +
+		(diffuseColor * ambientIntensity);
+}

Tut 10 Shinies/data/PosTransform.vert

+#version 330
+
+layout(location = 0) in vec3 position;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
+}

Tut 10 Shinies/data/UniformColor.frag

+#version 330
+
+uniform vec4 objectColor;
+
+out vec4 outputColor;
+
+void main()
+{
+	outputColor = objectColor;
+}

Tut 10 Shinies/data/UnitCube.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="3" > 
+        0.5 0.5 0.5
+        0.5 -0.5 0.5
+        -0.5 -0.5 0.5
+        -0.5 0.5 0.5
+        0.5 0.5 0.5
+        -0.5 0.5 0.5
+        -0.5 0.5 -0.5
+        0.5 0.5 -0.5
+        0.5 0.5 0.5
+        0.5 0.5 -0.5
+        0.5 -0.5 -0.5
+        0.5 -0.5 0.5
+        0.5 0.5 -0.5
+        -0.5 0.5 -0.5
+        -0.5 -0.5 -0.5
+        0.5 -0.5 -0.5
+        0.5 -0.5 0.5
+        0.5 -0.5 -0.5
+        -0.5 -0.5 -0.5
+        -0.5 -0.5 0.5
+        -0.5 0.5 0.5
+        -0.5 -0.5 0.5
+        -0.5 -0.5 -0.5
+        -0.5 0.5 -0.5</attribute>
+	<attribute index="1" type="float" size="4" > 
+        0 1 0 1
+        0 1 0 1
+        0 1 0 1
+        0 1 0 1
+        0 0 1 1
+        0 0 1 1
+        0 0 1 1
+        0 0 1 1
+        1 0 0 1
+        1 0 0 1
+        1 0 0 1
+        1 0 0 1
+        1 1 0 1
+        1 1 0 1
+        1 1 0 1
+        1 1 0 1
+        0 1 1 1
+        0 1 1 1
+        0 1 1 1
+        0 1 1 1
+        1 0 1 1
+        1 0 1 1
+        1 0 1 1
+        1 0 1 1</attribute>
+	<vao name="color" >
+		<source attrib="0" />
+		<source attrib="1" />
+	</vao>
+	<vao name="flat" >
+		<source attrib="0" />
+	</vao>
+	<indices cmd="triangles" type="ushort" > 
+        0 1 2
+        2 3 0
+        4 5 6
+        6 7 4
+        8 9 10
+        10 11 8
+        12 13 14
+        14 15 12
+        16 17 18
+        18 19 16
+        20 21 22
+        22 23 20</indices>
+</mesh>

Tut 10 Shinies/data/UnitCylinder.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="3" > 
+        0 0.5 0
+        0.5 0.5 0
+        0.5 -0.5 0
+        0.48907381875731 0.5 0.1039557588888
+        0.48907381875731 -0.5 0.1039557588888
+        0.45677280077542 0.5 0.20336815992623
+        0.45677280077542 -0.5 0.20336815992623
+        0.40450865316151 0.5 0.29389241146627
+        0.40450865316151 -0.5 0.29389241146627
+        0.33456556611288 0.5 0.37157217599218
+        0.33456556611288 -0.5 0.37157217599218
+        0.2500003830126 0.5 0.43301248075957
+        0.2500003830126 -0.5 0.43301248075957
+        0.15450900193016 0.5 0.47552809414644
+        0.15450900193016 -0.5 0.47552809414644
+        0.052264847412855 0.5 0.49726088296277
+        0.052264847412855 -0.5 0.49726088296277
+        -0.052263527886268 0.5 0.49726102165048
+        -0.052263527886268 -0.5 0.49726102165048
+        -0.15450774007312 0.5 0.47552850414828
+        -0.15450774007312 -0.5 0.47552850414828
+        -0.24999923397422 0.5 0.43301314415651
+        -0.24999923397422 -0.5 0.43301314415651
+        -0.33456458011157 0.5 0.37157306379065
+        -0.33456458011157 -0.5 0.37157306379065
+        -0.40450787329018 0.5 0.29389348486527
+        -0.40450787329018 -0.5 0.29389348486527
+        -0.45677226111814 0.5 0.20336937201315
+        -0.45677226111814 -0.5 0.20336937201315
+        -0.48907354289964 0.5 0.10395705668972
+        -0.48907354289964 -0.5 0.10395705668972
+        -0.49999999999824 0.5 1.3267948966764e-006
+        -0.49999999999824 -0.5 1.3267948966764e-006
+        -0.48907409461153 0.5 -0.10395446108714
+        -0.48907409461153 -0.5 -0.10395446108714
+        -0.45677334042948 0.5 -0.20336694783787
+        -0.45677334042948 -0.5 -0.20336694783787
+        -0.40450943302999 0.5 -0.2938913380652
+        -0.40450943302999 -0.5 -0.2938913380652
+        -0.33456655211184 0.5 -0.3715712881911
+        -0.33456655211184 -0.5 -0.3715712881911
+        -0.25000153204922 0.5 -0.43301181735958
+        -0.25000153204922 -0.5 -0.43301181735958
+        -0.15451026378611 0.5 -0.47552768414126
+        -0.15451026378611 -0.5 -0.47552768414126
+        -0.052266166939075 0.5 -0.49726074427155
+        -0.052266166939075 -0.5 -0.49726074427155
+        0.052262208359312 0.5 -0.4972611603347
+        0.052262208359312 -0.5 -0.4972611603347
+        0.15450647821499 0.5 -0.47552891414676
+        0.15450647821499 -0.5 -0.47552891414676
+        0.24999808493408 0.5 -0.4330138075504
+        0.24999808493408 -0.5 -0.4330138075504
+        0.3345635941079 0.5 -0.37157395158649
+        0.3345635941079 -0.5 -0.37157395158649
+        0.40450709341601 0.5 -0.2938945582622
+        0.40450709341601 -0.5 -0.2938945582622
+        0.45677172145764 0.5 -0.20337058409865
+        0.45677172145764 -0.5 -0.20337058409865
+        0.48907326703854 0.5 -0.10395835448992
+        0.48907326703854 -0.5 -0.10395835448992
+        0 -0.5 0
+        0.5 0.5 0
+        0.5 -0.5 0
+        0.48907381875731 0.5 0.1039557588888
+        0.48907381875731 -0.5 0.1039557588888
+        0.45677280077542 0.5 0.20336815992623
+        0.45677280077542 -0.5 0.20336815992623
+        0.40450865316151 0.5 0.29389241146627
+        0.40450865316151 -0.5 0.29389241146627
+        0.33456556611288 0.5 0.37157217599218
+        0.33456556611288 -0.5 0.37157217599218
+        0.2500003830126 0.5 0.43301248075957
+        0.2500003830126 -0.5 0.43301248075957
+        0.15450900193016 0.5 0.47552809414644
+        0.15450900193016 -0.5 0.47552809414644
+        0.052264847412855 0.5 0.49726088296277
+        0.052264847412855 -0.5 0.49726088296277
+        -0.052263527886268 0.5 0.49726102165048
+        -0.052263527886268 -0.5 0.49726102165048
+        -0.15450774007312 0.5 0.47552850414828
+        -0.15450774007312 -0.5 0.47552850414828
+        -0.24999923397422 0.5 0.43301314415651
+        -0.24999923397422 -0.5 0.43301314415651
+        -0.33456458011157 0.5 0.37157306379065
+        -0.33456458011157 -0.5 0.37157306379065
+        -0.40450787329018 0.5 0.29389348486527
+        -0.40450787329018 -0.5 0.29389348486527
+        -0.45677226111814 0.5 0.20336937201315
+        -0.45677226111814 -0.5 0.20336937201315
+        -0.48907354289964 0.5 0.10395705668972
+        -0.48907354289964 -0.5 0.10395705668972
+        -0.49999999999824 0.5 1.3267948966764e-006
+        -0.49999999999824 -0.5 1.3267948966764e-006
+        -0.48907409461153 0.5 -0.10395446108714
+        -0.48907409461153 -0.5 -0.10395446108714
+        -0.45677334042948 0.5 -0.20336694783787
+        -0.45677334042948 -0.5 -0.20336694783787
+        -0.40450943302999 0.5 -0.2938913380652
+        -0.40450943302999 -0.5 -0.2938913380652
+        -0.33456655211184 0.5 -0.3715712881911
+        -0.33456655211184 -0.5 -0.3715712881911
+        -0.25000153204922 0.5 -0.43301181735958
+        -0.25000153204922 -0.5 -0.43301181735958
+        -0.15451026378611 0.5 -0.47552768414126
+        -0.15451026378611 -0.5 -0.47552768414126
+        -0.052266166939075 0.5 -0.49726074427155
+        -0.052266166939075 -0.5 -0.49726074427155
+        0.052262208359312 0.5 -0.4972611603347
+        0.052262208359312 -0.5 -0.4972611603347
+        0.15450647821499 0.5 -0.47552891414676
+        0.15450647821499 -0.5 -0.47552891414676
+        0.24999808493408 0.5 -0.4330138075504
+        0.24999808493408 -0.5 -0.4330138075504
+        0.3345635941079 0.5 -0.37157395158649
+        0.3345635941079 -0.5 -0.37157395158649
+        0.40450709341601 0.5 -0.2938945582622
+        0.40450709341601 -0.5 -0.2938945582622
+        0.45677172145764 0.5 -0.20337058409865
+        0.45677172145764 -0.5 -0.20337058409865
+        0.48907326703854 0.5 -0.10395835448992
+        0.48907326703854 -0.5 -0.10395835448992</attribute>
+	<attribute index="1" type="float" size="4" > 
+        1 1 1 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        1 1 1 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.9 0.5 0.5 1
+        0.9 0.5 0.5 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.5 0.1 0.1 1
+        0.5 0.1 0.1 1
+        0.58 0.18 0.18 1
+        0.58 0.18 0.18 1
+        0.66 0.26 0.26 1
+        0.66 0.26 0.26 1
+        0.74 0.34 0.34 1
+        0.74 0.34 0.34 1
+        0.82 0.42 0.42 1
+        0.82 0.42 0.42 1</attribute>
+	<attribute index="2" type="float" size="3" > 
+        0 1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 1 0
+        0 -1 0
+        0 -1 0
+        1 0 0
+        1 0 0
+        0.97814763751461 0 0.20791151777759
+        0.97814763751461 0 0.20791151777759
+        0.91354560155084 0 0.40673631985245
+        0.91354560155084 0 0.40673631985245
+        0.80901730632302 0 0.58778482293254
+        0.80901730632302 0 0.58778482293254
+        0.66913113222576 0 0.74314435198437
+        0.66913113222576 0 0.74314435198437
+        0.5000007660252 0 0.86602496151913
+        0.5000007660252 0 0.86602496151913
+        0.30901800386032 0 0.95105618829288
+        0.30901800386032 0 0.95105618829288
+        0.10452969482571 0 0.99452176592553
+        0.10452969482571 0 0.99452176592553
+        -0.10452705577254 0 0.99452204330096
+        -0.10452705577254 0 0.99452204330096
+        -0.30901548014624 0 0.95105700829655
+        -0.30901548014624 0 0.95105700829655
+        -0.49999846794844 0 0.86602628831301
+        -0.49999846794844 0 0.86602628831301
+        -0.66912916022314 0 0.7431461275813
+        -0.66912916022314 0 0.7431461275813
+        -0.80901574658037 0 0.58778696973054
+        -0.80901574658037 0 0.58778696973054
+        -0.91354452223627 0 0.40673874402631
+        -0.91354452223627 0 0.40673874402631
+        -0.97814708579929 0 0.20791411337945
+        -0.97814708579929 0 0.20791411337945
+        -0.99999999999648 0 2.6535897933527e-006
+        -0.99999999999648 0 2.6535897933527e-006
+        -0.97814818922305 0 -0.20790892217427
+        -0.97814818922305 0 -0.20790892217427
+        -0.91354668085897 0 -0.40673389567574
+        -0.91354668085897 0 -0.40673389567574
+        -0.80901886605998 0 -0.58778267613041
+        -0.80901886605998 0 -0.58778267613041
+        -0.66913310422368 0 -0.74314257638221
+        -0.66913310422368 0 -0.74314257638221
+        -0.50000306409843 0 -0.86602363471916
+        -0.50000306409843 0 -0.86602363471916
+        -0.30902052757222 0 -0.95105536828251
+        -0.30902052757222 0 -0.95105536828251
+        -0.10453233387815 0 -0.9945214885431
+        -0.10453233387815 0 -0.9945214885431
+        0.10452441671862 0 -0.99452232066939
+        0.10452441671862 0 -0.99452232066939
+        0.30901295642998 0 -0.95105782829353
+        0.30901295642998 0 -0.95105782829353
+        0.49999616986816 0 -0.8660276151008
+        0.49999616986816 0 -0.8660276151008
+        0.66912718821581 0 -0.74314790317299
+        0.66912718821581 0 -0.74314790317299
+        0.80901418683202 0 -0.5877891165244
+        0.80901418683202 0 -0.5877891165244
+        0.91354344291528 0 -0.40674116819729
+        0.91354344291528 0 -0.40674116819729
+        0.97814653407707 0 -0.20791670897984
+        0.97814653407707 0 -0.20791670897984</attribute>
+	<vao name="tint" >
+		<source attrib="0" />
+		<source attrib="1" />
+		<source attrib="2" />
+	</vao>
+	<vao name="flat" >
+		<source attrib="0" />
+		<source attrib="2" />
+	</vao>
+	<vao name="tint-unlit" >
+		<source attrib="0" />
+		<source attrib="1" />
+	</vao>
+	<indices cmd="tri-fan" type="ushort" >0 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 1</indices>
+	<indices cmd="tri-fan" type="ushort" >61 60 58 56 54 52 50 48 46 44 42 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 60</indices>
+	<indices cmd="tri-strip" type="ushort" >62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 62 63</indices>
+</mesh>

Tut 10 Shinies/data/UnitPlane.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="3" > 
+        0.5 0 -0.5
+        0.5 0 0.5
+        -0.5 0 0.5
+        -0.5 0 -0.5
+        0.5 0 -0.5
+        0.5 0 0.5
+        -0.5 0 0.5
+        -0.5 0 -0.5</attribute>
+	<attribute index="2" type="float" size="3" > 
+        0 1 0
+        0 1 0
+        0 1 0
+        0 1 0
+        0 -1 0
+        0 -1 0
+        0 -1 0
+        0 -1 0</attribute>
+	<indices cmd="triangles" type="ushort" > 
+        0 1 2
+        2 3 0
+        4 6 5
+        6 4 7</indices>
+</mesh>

Tut 10 Shinies/premake4.lua

+
+dofile("../framework/framework.lua")
+
+SetupSolution("Tutorial10")
+
+dofile("tutorials.lua")

Tut 10 Shinies/tutorials.lua

+
+SetupProject("Tut 10 Phong Lighting", "Phong Lighting.cpp",
+	"data/PCN.vert",
+	"data/PN.vert",
+	"data/PosTransform.vert",
+	"data/UniformColor.frag",
+	"data/NoPhong.frag",
+	"data/PhongOnly.frag",
+	"data/PhongLighting.frag")
+