Commits

Jason McKesson committed f781309

Fix for timer bug. Tut12 has ground again, and more real shaders.

Comments (0)

Files changed (24)

Tut 12 Dynamic Range/Scene Lighting.cpp

 #include "../framework/MatrixStack.h"
 #include "../framework/MousePole.h"
 #include "../framework/ObjectPole.h"
+#include "../framework/Timer.h"
 #include <glm/glm.hpp>
 #include <glm/gtc/type_ptr.hpp>
 
 float g_fzNear = 1.0f;
 float g_fzFar = 1000.0f;
 
-enum LightingModel
+enum LightingModels
 {
-	LM_GAUSSIAN_SPECULAR = 0,
-	LM_GAUSSIAN_ONLY,
+	LM_VERT_COLOR_DIFFUSE_SPECULAR = 0,
+	LM_VERT_COLOR_DIFFUSE,
 
 	LM_MAX_LIGHTING_MODEL,
 };
 
-struct ProgramPairs
+struct Shaders
 {
-	ProgramData whiteProg;
-	ProgramData colorProg;
+	const char *fileVertexShader;
+	const char *fileFragmentShader;
 };
 
-struct ShaderPairs
+ProgramData g_Programs[LM_MAX_LIGHTING_MODEL];
+Shaders g_ShaderFiles[LM_MAX_LIGHTING_MODEL] =
 {
-	const char *strWhiteVertShader;
-	const char *strColorVertShader;
-	const char *strFragmentShader;
-};
-
-ProgramPairs g_Programs[LM_MAX_LIGHTING_MODEL];
-ShaderPairs g_ShaderFiles[LM_MAX_LIGHTING_MODEL] =
-{
-	{"PN.vert", "PCN.vert", "ShowLighting.frag"},
-	{"PN.vert", "PCN.vert", "ShowNormals.frag"},
+	{"PCN.vert", "DiffuseSpecular.frag"},
+	{"PCN.vert", "DiffuseOnly.frag"},
 };
 
 UnlitProgData g_Unlit;
 {
 	for(int iProg = 0; iProg < LM_MAX_LIGHTING_MODEL; iProg++)
 	{
-		g_Programs[iProg].whiteProg = LoadLitProgram(
-			g_ShaderFiles[iProg].strWhiteVertShader, g_ShaderFiles[iProg].strFragmentShader);
-		g_Programs[iProg].colorProg = LoadLitProgram(
-			g_ShaderFiles[iProg].strColorVertShader, g_ShaderFiles[iProg].strFragmentShader);
+		g_Programs[iProg] = LoadLitProgram(
+			g_ShaderFiles[iProg].fileVertexShader, g_ShaderFiles[iProg].fileFragmentShader);
 	}
 
 	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
 glm::vec3 objectCenter = glm::vec3(0.0f, 0.0f, 0.0f);
 
 Framework::MousePole g_mousePole(objectCenter, radiusDef);
-Framework::ObjectPole g_objectPole(objectCenter, &g_mousePole);
 
 namespace
 {
 	void MouseMotion(int x, int y)
 	{
 		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
-		g_objectPole.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));
-		g_objectPole.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));
-		g_objectPole.GLUTMouseWheel(direction, glm::ivec2(x, y));
 		glutPostRedisplay();
 	}
 }
 
 	try
 	{
-		g_pTerrainMesh = new Framework::Mesh("UnitSphere.xml");
+		g_pTerrainMesh = new Framework::Mesh("Ground.xml");
 		g_pLightMesh = new Framework::Mesh("UnitCube.xml");
 	}
 	catch(std::exception &except)
 }
 
 static float g_fLightHeight = 1.5f;
-static float g_fLightRadius = 40.0f;
-static bool g_bRotateLight = true;
+static float g_fLightRadius = 70.0f;
+
+Framework::Timer g_lightTimer(Framework::Timer::TT_LOOP, 5.0f);
 
 static float g_fRotateTime = 0.0f;
 static float g_fPrevTime = 0.0f;
 
 glm::vec4 CalcLightPosition()
 {
+	g_lightTimer.Update();
+
 	const float fLoopDuration = 5.0f;
-	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+	const float fScale = 3.14159f * 2.0f;
 
-	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);
+	float timeThroughLoop = g_lightTimer.GetAlpha();
 
 	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;
+	ret.x = cosf(timeThroughLoop * fScale) * g_fLightRadius;
+	ret.z = sinf(timeThroughLoop * fScale) * g_fLightRadius;
 
 	return ret;
 }
 
-static int g_eLightModel = LM_GAUSSIAN_SPECULAR;
-
-bool IsGuassianLightModel()
-{
-	return (g_eLightModel == LM_GAUSSIAN_ONLY || g_eLightModel == LM_GAUSSIAN_SPECULAR);
-}
-
-static bool g_bUseFragmentLighting = true;
-static bool g_bDrawColoredCyl = false;
-static bool g_bDrawLightSource = false;
-static bool g_bScaleCyl = false;
-static bool g_bDrawDark = false;
-
 const float g_fLightAttenuation = 1.0f / (50.0f * 50.0f);
 
 const glm::vec4 g_darkColor(0.2f, 0.2f, 0.2f, 1.0f);
 const glm::vec4 g_lightColor(1.0f);
 
-class MaterialParams
-{
-public:
-	MaterialParams()
-		: m_fPhongExponent(4.0f)
-		, m_fBlinnExponent(4.0f)
-		, m_fGaussianRoughness(0.5f)
-	{}
-
-	operator float() const
-	{
-		return GetSpecularValue();
-	}
-
-	void Increment(bool bIsLarge)
-	{
-		float &theParam = GetSpecularValue();
-		if(IsGuassianLightModel())
-		{
-			if(bIsLarge)
-				theParam += 0.1f;
-			else
-				theParam += 0.01f;
-		}
-		else
-		{
-			if(bIsLarge)
-				theParam += 0.5f;
-			else
-				theParam += 0.1f;
-		}
-
-		ClampParam();
-	}
-
-	void Decrement(bool bIsLarge)
-	{
-		float &theParam = GetSpecularValue();
-		if(IsGuassianLightModel())
-		{
-			if(bIsLarge)
-				theParam -= 0.1f;
-			else
-				theParam -= 0.01f;
-		}
-		else
-		{
-			if(bIsLarge)
-				theParam -= 0.5f;
-			else
-				theParam -= 0.1f;
-		}
-
-		ClampParam();
-	}
-
-private:
-	float m_fPhongExponent;
-	float m_fBlinnExponent;
-	float m_fGaussianRoughness;
-
-	float &GetSpecularValue()
-	{
-		switch(g_eLightModel)
-		{
-		case LM_GAUSSIAN_SPECULAR:
-		case LM_GAUSSIAN_ONLY:
-			return m_fGaussianRoughness;
-		}
-
-		static float fStopComplaint = 0.0f;
-		return fStopComplaint;
-	}
-
-	const float &GetSpecularValue() const
-	{
-		switch(g_eLightModel)
-		{
-		case LM_GAUSSIAN_SPECULAR:
-		case LM_GAUSSIAN_ONLY:
-			return m_fGaussianRoughness;
-		}
-
-		static float fStopComplaint = 0.0f;
-		return fStopComplaint;
-	}
-
-	void ClampParam()
-	{
-		float &theParam = GetSpecularValue();
-
-		if(IsGuassianLightModel())
-		{
-			//Clamp to (0, 1].
-			theParam = std::max(0.00001f, theParam);
-			theParam = std::min(1.0f, theParam);
-		}
-		else
-		{
-			if(theParam <= 0.0f)
-				theParam = 0.0001f;
-		}
-	}
-};
-
-static MaterialParams g_matParams;
-
 //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.
 		const glm::vec4 &worldLightPos = CalcLightPosition();
 		const glm::vec4 &lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
 
-		ProgramData &whiteProg = g_Programs[g_eLightModel].whiteProg;
-		ProgramData &colorProg = g_Programs[g_eLightModel].colorProg;
+		ProgramData &prog = g_Programs[LM_VERT_COLOR_DIFFUSE];
 
-		glUseProgram(whiteProg.theProgram);
-		glUniform4f(whiteProg.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(whiteProg.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUniform3fv(whiteProg.cameraSpaceLightPosUnif,1, glm::value_ptr(lightPosCameraSpace));
-		glUniform1f(whiteProg.lightAttenuationUnif, g_fLightAttenuation);
-		glUniform1f(whiteProg.shininessFactorUnif, g_matParams);
-		glUniform4fv(whiteProg.baseDiffuseColorUnif, 1,
-			g_bDrawDark ? glm::value_ptr(g_darkColor) : glm::value_ptr(g_lightColor));
-
-		glUseProgram(colorProg.theProgram);
-		glUniform4f(colorProg.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(colorProg.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUniform3fv(colorProg.cameraSpaceLightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
-		glUniform1f(colorProg.lightAttenuationUnif, g_fLightAttenuation);
-		glUniform1f(colorProg.shininessFactorUnif, g_matParams);
+		glUseProgram(prog.theProgram);
+		glUniform4f(prog.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
+		glUniform4f(prog.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
+		glUniform3fv(prog.cameraSpaceLightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
+		glUniform1f(prog.lightAttenuationUnif, g_fLightAttenuation);
+		glUniform1f(prog.shininessFactorUnif, 0.5f);
 		glUseProgram(0);
 
 		{
 			{
 				Framework::MatrixStackPusher push(modelMatrix);
 				modelMatrix.RotateX(-90);
-				modelMatrix.Scale(20.0f, 20.0f, 20.0f);
 
 				glm::mat3 normMatrix(modelMatrix.Top());
 				normMatrix = glm::transpose(glm::inverse(normMatrix));
 
-				glUseProgram(colorProg.theProgram);
-				glUniformMatrix4fv(colorProg.modelToCameraMatrixUnif, 1, GL_FALSE,
+				glUseProgram(prog.theProgram);
+				glUniformMatrix4fv(prog.modelToCameraMatrixUnif, 1, GL_FALSE,
 					glm::value_ptr(modelMatrix.Top()));
 
-				glUniformMatrix3fv(colorProg.normalModelToCameraMatrixUnif, 1, GL_FALSE,
+				glUniformMatrix3fv(prog.normalModelToCameraMatrixUnif, 1, GL_FALSE,
 					glm::value_ptr(normMatrix));
-				g_pTerrainMesh->Render("tint");
+				g_pTerrainMesh->Render();
 				glUseProgram(0);
 			}
 
 			//Render the light
-			if(g_bDrawLightSource)
 			{
 				Framework::MatrixStackPusher push(modelMatrix);
 
 {
 	Framework::MatrixStack persMatrix;
 	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
-	const glm::mat4 &invMat = glm::inverse(persMatrix.Top());
 
 	for(int iProg = 0; iProg < LM_MAX_LIGHTING_MODEL; iProg++)
 	{
-		g_Programs[iProg].whiteProg.SetWindowData(persMatrix.Top());
-		g_Programs[iProg].colorProg.SetWindowData(persMatrix.Top());
+		g_Programs[iProg].SetWindowData(persMatrix.Top());
 	}
 
 	g_Unlit.SetWindowData(persMatrix.Top());
 	glutPostRedisplay();
 }
 
-static const char *strLightModelNames[] =
-{
-	"Gaussian Specular.",
-	"Gaussian Only",
-};
-
 
 //Called whenever a key on the keyboard was pressed.
 //The key is given by the ''key'' parameter, which is in ASCII.
 		glutLeaveMainLoop();
 		break;
 		
-	case 32:
-		g_bDrawColoredCyl = !g_bDrawColoredCyl;
-		break;
-
 	case 'i': g_fLightHeight += 2.f; break;
 	case 'k': g_fLightHeight -= 2.f; break;
 	case 'l': g_fLightRadius += 2.f; break;
 	case 'L': g_fLightRadius += 0.5f; break;
 	case 'J': g_fLightRadius -= 0.5f; break;
 
-	case 'o': g_matParams.Increment(true); bChangedShininess = true; break;
-	case 'u': g_matParams.Decrement(true); bChangedShininess = true; break;
-	case 'O': g_matParams.Increment(false); bChangedShininess = true; break;
-	case 'U': g_matParams.Decrement(false); bChangedShininess = true; break;
-
-	case 'y': g_bDrawLightSource = !g_bDrawLightSource; break;
-	case 't': g_bScaleCyl = !g_bScaleCyl; break;
-	case 'b': g_bRotateLight = !g_bRotateLight; break;
-	case 'g': g_bDrawDark = !g_bDrawDark; break;
-	case 'h':
-		if(g_eLightModel % 2)
-			g_eLightModel -= 1;
-		else
-			g_eLightModel += 1;
-		g_eLightModel %= LM_MAX_LIGHTING_MODEL;
-		bChangedLightModel = true;
-		break;
+	case 'b': g_lightTimer.TogglePause(); break;
 	}
 
 	if(g_fLightRadius < 0.2f)
 		g_fLightRadius = 0.2f;
 
-	if(bChangedShininess)
-		printf("Shiny: %f\n", (float)g_matParams);
-
-	if(bChangedLightModel)
-		printf("%s\n", strLightModelNames[g_eLightModel]);
-
 	glutPostRedisplay();
 }
 

Tut 12 Dynamic Range/data/DiffuseOnly.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
+uniform float shininessFactor;
+
+
+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 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);
+	
+	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+		(diffuseColor * ambientIntensity);
+}

Tut 12 Dynamic Range/data/DiffuseSpecular.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
+uniform float shininessFactor;
+
+
+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 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);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+	float exponent = angleNormalHalf / shininessFactor;
+	exponent = -(exponent * exponent);
+	float gaussianTerm = exp(exponent);
+
+	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
+
+	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+		(specularColor * attenIntensity * gaussianTerm) +
+		(diffuseColor * ambientIntensity);
+}

Tut 12 Dynamic Range/data/GenSphere.lua

 		local point = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
 		positions[#positions + 1] = 0.5 * point;
 		normals[#normals + 1] = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
-		colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+		colors[#colors + 1] = vmath.vec4(
+			vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho), 1.0);
 	end
 end
 

Tut 12 Dynamic Range/data/PCN.vert

 
 out vec4 diffuseColor;
 out vec3 vertexNormal;
-out vec3 modelSpaceNormal;
 out vec3 cameraSpacePosition;
 
 uniform mat4 cameraToClipMatrix;
 	gl_Position = cameraToClipMatrix * tempCamPosition;
 
 	vertexNormal = normalize(normalModelToCameraMatrix * normal);
-	modelSpaceNormal = normalize(normal);
 	diffuseColor = inDiffuseColor;
 	cameraSpacePosition = vec3(tempCamPosition);
 }

Tut 12 Dynamic Range/data/PCNLighting.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;
+out vec3 modelSpaceNormal;
+out vec3 cameraSpacePosition;
+
+smooth out vec4 passthrough;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+uniform mat3 normalModelToCameraMatrix;
+
+uniform vec3 cameraSpaceLightPos;
+
+void main()
+{
+	vec4 tempCamPosition = (modelToCameraMatrix * vec4(position, 1.0));
+	gl_Position = cameraToClipMatrix * tempCamPosition;
+
+	vec3 cameraNormal = normalize(normalModelToCameraMatrix * normal);
+	vertexNormal = cameraNormal;
+	modelSpaceNormal = normalize(normal);
+	diffuseColor = inDiffuseColor;
+	cameraSpacePosition = tempCamPosition.xyz;
+	
+	vec3 lightDir = normalize(cameraSpaceLightPos - tempCamPosition.xyz);
+	vec3 surfaceNormal = normalize(cameraNormal);
+	passthrough = vec4(dot(surfaceNormal, lightDir));
+
+}

Tut 12 Dynamic Range/data/PN.vert

 
 out vec4 diffuseColor;
 out vec3 vertexNormal;
-out vec3 modelSpaceNormal;
 out vec3 cameraSpacePosition;
 
 uniform mat4 cameraToClipMatrix;
 	gl_Position = cameraToClipMatrix * tempCamPosition;
 
 	vertexNormal = normalize(normalModelToCameraMatrix * normal);
-	modelSpaceNormal = normalize(normal);
 	diffuseColor = baseDiffuseColor;
 	cameraSpacePosition = vec3(tempCamPosition);
 }

Tut 12 Dynamic Range/data/Passthrough.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 modelSpaceNormal;
+in vec3 cameraSpacePosition;
+
+smooth in vec4 passthrough;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
+uniform float shininessFactor;
+
+
+void main()
+{
+	outputColor = passthrough;
+}

Tut 12 Dynamic Range/data/ShowLighting.frag

 #version 330
 
 in vec4 diffuseColor;
-in vec3 vertexNormal;
+smooth in vec3 vertexNormal;
 in vec3 modelSpaceNormal;
 in vec3 cameraSpacePosition;
 

Tut 12 Dynamic Range/data/ShowNormals.frag

 #version 330
 
 in vec4 diffuseColor;
-in vec3 vertexNormal;
+smooth in vec3 vertexNormal;
 in vec3 modelSpaceNormal;
 in vec3 cameraSpacePosition;
 

Tut 12 Dynamic Range/data/UnitSphere.xml

         0 -0.5 0</attribute>
 	<attribute index="1" type="float" size="4" > 
         1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
-        1 1 1 1
+        0.5 0.86602540378444 0 1
+        0.40450849718747 0.86602540378444 0.29389262614624 1
+        0.15450849718747 0.86602540378444 0.47552825814758 1
+        -0.15450849718747 0.86602540378444 0.47552825814758 1
+        -0.40450849718747 0.86602540378444 0.29389262614624 1
+        -0.5 0.86602540378444 6.1230317691119e-017 1
+        -0.40450849718747 0.86602540378444 -0.29389262614624 1
+        -0.15450849718747 0.86602540378444 -0.47552825814758 1
+        0.15450849718747 0.86602540378444 -0.47552825814758 1
+        0.40450849718747 0.86602540378444 -0.29389262614624 1
+        0.86602540378444 0.5 0 1
+        0.70062926922204 0.5 0.50903696045513 1
+        0.26761656732982 0.5 0.82363910354633 1
+        -0.26761656732982 0.5 0.82363910354633 1
+        -0.70062926922204 0.5 0.50903696045513 1
+        -0.86602540378444 0.5 1.060540212046e-016 1
+        -0.70062926922204 0.5 -0.50903696045513 1
+        -0.26761656732982 0.5 -0.82363910354633 1
+        0.26761656732982 0.5 -0.82363910354633 1
+        0.70062926922204 0.5 -0.50903696045513 1
+        1 6.1230317691119e-017 0 1
+        0.80901699437495 6.1230317691119e-017 0.58778525229247 1
+        0.30901699437495 6.1230317691119e-017 0.95105651629515 1
+        -0.30901699437495 6.1230317691119e-017 0.95105651629515 1
+        -0.80901699437495 6.1230317691119e-017 0.58778525229247 1
+        -1 6.1230317691119e-017 1.2246063538224e-016 1
+        -0.80901699437495 6.1230317691119e-017 -0.58778525229247 1
+        -0.30901699437495 6.1230317691119e-017 -0.95105651629515 1
+        0.30901699437495 6.1230317691119e-017 -0.95105651629515 1
+        0.80901699437495 6.1230317691119e-017 -0.58778525229247 1
+        0.86602540378444 -0.5 0 1
+        0.70062926922204 -0.5 0.50903696045513 1
+        0.26761656732982 -0.5 0.82363910354633 1
+        -0.26761656732982 -0.5 0.82363910354633 1
+        -0.70062926922204 -0.5 0.50903696045513 1
+        -0.86602540378444 -0.5 1.060540212046e-016 1
+        -0.70062926922204 -0.5 -0.50903696045513 1
+        -0.26761656732982 -0.5 -0.82363910354633 1
+        0.26761656732982 -0.5 -0.82363910354633 1
+        0.70062926922204 -0.5 -0.50903696045513 1
+        0.5 -0.86602540378444 0 1
+        0.40450849718747 -0.86602540378444 0.29389262614624 1
+        0.15450849718747 -0.86602540378444 0.47552825814758 1
+        -0.15450849718747 -0.86602540378444 0.47552825814758 1
+        -0.40450849718747 -0.86602540378444 0.29389262614624 1
+        -0.5 -0.86602540378444 6.1230317691119e-017 1
+        -0.40450849718747 -0.86602540378444 -0.29389262614624 1
+        -0.15450849718747 -0.86602540378444 -0.47552825814758 1
+        0.15450849718747 -0.86602540378444 -0.47552825814758 1
+        0.40450849718747 -0.86602540378444 -0.29389262614624 1
         1 1 1 1</attribute>
 	<attribute index="2" type="float" size="3" > 
         0 1 0

Tut 12 Dynamic Range/tutorials.lua

 
-SetupProject("Tut 12 Scene Lighting", "Scene Lighting.cpp")
+SetupProject("Tut 12 Scene Lighting", "Scene Lighting.cpp",
+	"PNC.vert", "PN.vert", "DiffuseSpecular.frag", "DiffuseOnly.frag",
+)
 

Tut 13 Imposters/BasicImposter.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 "../framework/ObjectPole.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 lightAttenuationUnif;
+	GLuint shininessFactorUnif;
+	GLuint baseDiffuseColorUnif;
+
+	void SetWindowData(const glm::mat4 cameraToClip)
+	{
+		glUseProgram(theProgram);
+		glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE,
+			glm::value_ptr(cameraToClip));
+		glUseProgram(0);
+	}
+};
+
+struct UnlitProgData
+{
+	GLuint theProgram;
+
+	GLuint objectColorUnif;
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+
+	void SetWindowData(const glm::mat4 cameraToClip)
+	{
+		glUseProgram(theProgram);
+		glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE,
+			glm::value_ptr(cameraToClip));
+		glUseProgram(0);
+	}
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+ProgramData g_LitObjects;
+
+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.lightAttenuationUnif = glGetUniformLocation(data.theProgram, "lightAttenuation");
+	data.shininessFactorUnif = glGetUniformLocation(data.theProgram, "shininessFactor");
+	data.baseDiffuseColorUnif = glGetUniformLocation(data.theProgram, "baseDiffuseColor");
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	g_LitObjects = LoadLitProgram("PN.vert", "Lighting.frag");
+
+	g_Unlit = LoadUnlitProgram("Unlit.vert", "Unlit.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};
+glm::vec3 objectCenter = glm::vec3(0.0f, 0.5f, 0.0f);
+
+Framework::MousePole g_mousePole(objectCenter, radiusDef);
+Framework::ObjectPole g_objectPole(objectCenter, &g_mousePole);
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
+		g_objectPole.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));
+		g_objectPole.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));
+		g_objectPole.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);
+}
+
+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;
+}
+
+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_bDrawLightSource = false;
+static bool g_bScaleCyl = false;
+static bool g_bDrawDark = false;
+
+const float g_fLightAttenuation = 1.2f;
+static float g_fShininessFactor = 4.0f;
+
+const glm::vec4 g_darkColor(0.2f, 0.2f, 0.2f, 1.0f);
+const glm::vec4 g_lightColor(1.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_LitObjects;
+			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);
+		glUniform4fv(pWhiteProg->baseDiffuseColorUnif, 1,
+			g_bDrawDark ? glm::value_ptr(g_darkColor) : glm::value_ptr(g_lightColor));
+
+		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.ApplyMatrix(g_objectPole.CalcMatrix());
+
+				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_bDrawLightSource)
+			{
+				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());
+
+	g_WhiteNoPhong.SetWindowData(persMatrix.Top());
+	g_ColorNoPhong.SetWindowData(persMatrix.Top());
+	g_WhitePhong.SetWindowData(persMatrix.Top());
+	g_ColorPhong.SetWindowData(persMatrix.Top());
+	g_LitObjects.SetWindowData(persMatrix.Top());
+	g_ColorPhongOnly.SetWindowData(persMatrix.Top());
+
+	g_Unlit.SetWindowData(persMatrix.Top());
+
+	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 32:
+		g_bDrawColoredCyl = !g_bDrawColoredCyl;
+		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 'O': g_fShininessFactor += 0.1f; bChangedShininess = true; break;
+	case 'U': g_fShininessFactor -= 0.1f; bChangedShininess = true; break;
+
+	case 'y': g_bDrawLightSource = !g_bDrawLightSource; break;
+	case 't': g_bScaleCyl = !g_bScaleCyl; break;
+	case 'b': g_bRotateLight = !g_bRotateLight; break;
+	case 'g': g_bDrawDark = !g_bDrawDark; 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 <= 0.0f)
+		g_fShininessFactor = 0.0001f;
+
+	if(bChangedShininess)
+		printf("Shiny: %f\n", g_fShininessFactor);
+
+	if(bChangedLightModel)
+		printf("%s\n", strLightModelNames[g_eLightModel]);
+
+	glutPostRedisplay();
+}
+

Tut 13 Imposters/data/GenSphere.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 strips = {};
+local restartIndex = 65535;
+
+local iSegCount, iColorRepeatCount, iRingCount = ...;
+iSegCount = iSegCount or 10;
+iColorRepeatCount = iColorRepeatCount or 3;
+iRingCount = iRingCount or 5;
+
+local rhoAngle = math.pi * 2.0 / iSegCount;
+local thetaAngle = math.pi / (iRingCount + 1);
+local iColorCycleAngle = math.pi * 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 vertex attributes
+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);
+
+local firstSideIx = #positions;
+
+for iRing = 1, iRingCount do
+	local theta = (thetaAngle * iRing)
+	local sinTheta, cosTheta = math.sin(theta), math.cos(theta);
+
+	for iSeg = 0, (iSegCount - 1) do
+		local rho = rhoAngle * iSeg;
+		local sinRho, cosRho = math.sin(rho), math.cos(rho);
+		
+		local point = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
+		positions[#positions + 1] = 0.5 * point;
+		normals[#normals + 1] = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
+		colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	end
+end
+
+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 cap fans.
+topFan[#topFan + 1] = 0;
+botFan[#botFan + 1] = #positions - 1;
+
+for iSeg = 1, iSegCount do
+	topFan[#topFan + 1] = iSeg;
+	botFan[#botFan + 1] = (#positions - 1) - iSeg;
+end
+
+topFan[#topFan + 1] = 1;
+botFan[#botFan + 1] = (#positions - 2);
+
+--Compute the strips.
+
+for iRing = 1, iRingCount - 1 do
+	local topRingStart = 1 + ((iRing - 1) * iSegCount);
+	local botRingStart = 1 + (iRing * iSegCount);
+	local strip = {};
+	strips[#strips + 1] = strip;
+	
+	for iSeg = 0, (iSegCount - 1) do
+		strip[#strip + 1] = topRingStart + iSeg;
+		strip[#strip + 1] = botRingStart + iSeg;
+	end
+
+	strip[#strip + 1] = topRingStart;
+	strip[#strip + 1] = botRingStart;
+end
+
+
+do
+	local writer = XmlWriter.XmlWriter("UnitSphere.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();
+		for i, strip in ipairs(strips) do
+			writer:PushElement("indices");
+				writer:AddAttribute("cmd", "tri-strip");
+				writer:AddAttribute("type", "ushort");
+				writer:AddText(table.concat(strip, " "));
+			writer:PopElement();
+		end
+	writer:PopElement();
+	writer:Close();
+end

Tut 13 Imposters/data/Lighting.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec3 modelSpaceLightPos;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
+uniform float shininessFactor;
+uniform vec4 baseDiffuseColor;
+
+
+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 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);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+	float phongTerm = dot(viewDirection, reflectDir);
+	phongTerm = clamp(phongTerm, 0, 1);
+	phongTerm = cosAngIncidence != 0.0 ? phongTerm : 0.0;
+	phongTerm = pow(phongTerm, shininessFactor);
+	
+
+	outputColor = (baseDiffuseColor * attenIntensity * cosAngIncidence) +
+		(specularColor * attenIntensity * phongTerm) +
+		(baseDiffuseColor * ambientIntensity);
+}

Tut 13 Imposters/data/PN.vert

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

Tut 13 Imposters/data/UnitSphere.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.25 0.43301270189222 0
+        0.20225424859374 0.43301270189222 0.14694631307312
+        0.077254248593737 0.43301270189222 0.23776412907379
+        -0.077254248593737 0.43301270189222 0.23776412907379
+        -0.20225424859374 0.43301270189222 0.14694631307312
+        -0.25 0.43301270189222 3.0615158845559e-017
+        -0.20225424859374 0.43301270189222 -0.14694631307312
+        -0.077254248593737 0.43301270189222 -0.23776412907379
+        0.077254248593737 0.43301270189222 -0.23776412907379
+        0.20225424859374 0.43301270189222 -0.14694631307312
+        0.43301270189222 0.25 0
+        0.35031463461102 0.25 0.25451848022756
+        0.13380828366491 0.25 0.41181955177317
+        -0.13380828366491 0.25 0.41181955177317
+        -0.35031463461102 0.25 0.25451848022756
+        -0.43301270189222 0.25 5.3027010602301e-017
+        -0.35031463461102 0.25 -0.25451848022756
+        -0.13380828366491 0.25 -0.41181955177317
+        0.13380828366491 0.25 -0.41181955177317
+        0.35031463461102 0.25 -0.25451848022756
+        0.5 3.0615158845559e-017 0
+        0.40450849718747 3.0615158845559e-017 0.29389262614624
+        0.15450849718747 3.0615158845559e-017 0.47552825814758
+        -0.15450849718747 3.0615158845559e-017 0.47552825814758
+        -0.40450849718747 3.0615158845559e-017 0.29389262614624
+        -0.5 3.0615158845559e-017 6.1230317691119e-017
+        -0.40450849718747 3.0615158845559e-017 -0.29389262614624
+        -0.15450849718747 3.0615158845559e-017 -0.47552825814758
+        0.15450849718747 3.0615158845559e-017 -0.47552825814758
+        0.40450849718747 3.0615158845559e-017 -0.29389262614624
+        0.43301270189222 -0.25 0
+        0.35031463461102 -0.25 0.25451848022756
+        0.13380828366491 -0.25 0.41181955177317
+        -0.13380828366491 -0.25 0.41181955177317
+        -0.35031463461102 -0.25 0.25451848022756
+        -0.43301270189222 -0.25 5.3027010602301e-017
+        -0.35031463461102 -0.25 -0.25451848022756
+        -0.13380828366491 -0.25 -0.41181955177317
+        0.13380828366491 -0.25 -0.41181955177317
+        0.35031463461102 -0.25 -0.25451848022756
+        0.25 -0.43301270189222 0
+        0.20225424859374 -0.43301270189222 0.14694631307312
+        0.077254248593737 -0.43301270189222 0.23776412907379
+        -0.077254248593737 -0.43301270189222 0.23776412907379
+        -0.20225424859374 -0.43301270189222 0.14694631307312
+        -0.25 -0.43301270189222 3.0615158845559e-017
+        -0.20225424859374 -0.43301270189222 -0.14694631307312
+        -0.077254248593737 -0.43301270189222 -0.23776412907379
+        0.077254248593737 -0.43301270189222 -0.23776412907379
+        0.20225424859374 -0.43301270189222 -0.14694631307312
+        0 -0.5 0</attribute>
+	<attribute index="1" type="float" size="4" > 
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1</attribute>
+	<attribute index="2" type="float" size="3" > 
+        0 1 0
+        0.5 0.86602540378444 0
+        0.40450849718747 0.86602540378444 0.29389262614624
+        0.15450849718747 0.86602540378444 0.47552825814758
+        -0.15450849718747 0.86602540378444 0.47552825814758
+        -0.40450849718747 0.86602540378444 0.29389262614624
+        -0.5 0.86602540378444 6.1230317691119e-017
+        -0.40450849718747 0.86602540378444 -0.29389262614624
+        -0.15450849718747 0.86602540378444 -0.47552825814758
+        0.15450849718747 0.86602540378444 -0.47552825814758
+        0.40450849718747 0.86602540378444 -0.29389262614624
+        0.86602540378444 0.5 0
+        0.70062926922204 0.5 0.50903696045513
+        0.26761656732982 0.5 0.82363910354633
+        -0.26761656732982 0.5 0.82363910354633
+        -0.70062926922204 0.5 0.50903696045513
+        -0.86602540378444 0.5 1.060540212046e-016
+        -0.70062926922204 0.5 -0.50903696045513
+        -0.26761656732982 0.5 -0.82363910354633
+        0.26761656732982 0.5 -0.82363910354633
+        0.70062926922204 0.5 -0.50903696045513
+        1 6.1230317691119e-017 0
+        0.80901699437495 6.1230317691119e-017 0.58778525229247
+        0.30901699437495 6.1230317691119e-017 0.95105651629515
+        -0.30901699437495 6.1230317691119e-017 0.95105651629515
+        -0.80901699437495 6.1230317691119e-017 0.58778525229247
+        -1 6.1230317691119e-017 1.2246063538224e-016
+        -0.80901699437495 6.1230317691119e-017 -0.58778525229247
+        -0.30901699437495 6.1230317691119e-017 -0.95105651629515
+        0.30901699437495 6.1230317691119e-017 -0.95105651629515
+        0.80901699437495 6.1230317691119e-017 -0.58778525229247
+        0.86602540378444 -0.5 0
+        0.70062926922204 -0.5 0.50903696045513
+        0.26761656732982 -0.5 0.82363910354633
+        -0.26761656732982 -0.5 0.82363910354633
+        -0.70062926922204 -0.5 0.50903696045513
+        -0.86602540378444 -0.5 1.060540212046e-016
+        -0.70062926922204 -0.5 -0.50903696045513
+        -0.26761656732982 -0.5 -0.82363910354633
+        0.26761656732982 -0.5 -0.82363910354633
+        0.70062926922204 -0.5 -0.50903696045513
+        0.5 -0.86602540378444 0
+        0.40450849718747 -0.86602540378444 0.29389262614624
+        0.15450849718747 -0.86602540378444 0.47552825814758
+        -0.15450849718747 -0.86602540378444 0.47552825814758
+        -0.40450849718747 -0.86602540378444 0.29389262614624
+        -0.5 -0.86602540378444 6.1230317691119e-017
+        -0.40450849718747 -0.86602540378444 -0.29389262614624
+        -0.15450849718747 -0.86602540378444 -0.47552825814758
+        0.15450849718747 -0.86602540378444 -0.47552825814758
+        0.40450849718747 -0.86602540378444 -0.29389262614624
+        0 -1 0</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 2 3 4 5 6 7 8 9 10 1</indices>
+	<indices cmd="tri-fan" type="ushort" >51 50 49 48 47 46 45 44 43 42 41 50</indices>
+	<indices cmd="tri-strip" type="ushort" >1 11 2 12 3 13 4 14 5 15 6 16 7 17 8 18 9 19 10 20 1 11</indices>
+	<indices cmd="tri-strip" type="ushort" >11 21 12 22 13 23 14 24 15 25 16 26 17 27 18 28 19 29 20 30 11 21</indices>
+	<indices cmd="tri-strip" type="ushort" >21 31 22 32 23 33 24 34 25 35 26 36 27 37 28 38 29 39 30 40 21 31</indices>
+	<indices cmd="tri-strip" type="ushort" >31 41 32 42 33 43 34 44 35 45 36 46 37 47 38 48 39 49 40 50 31 41</indices>
+</mesh>

Tut 13 Imposters/data/Unlit.frag

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

Tut 13 Imposters/data/Unlit.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 13 Imposters/premake4.lua

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

Tut 13 Imposters/tutorials.lua

+
+SetupProject("Tut 13 Basic Imposter", "BasicImposter.cpp",
+	"data/BasicImposter.vert",
+	"data/BasicImposter.frag",
+	"data/PN.vert",
+	"data/Lighting.frag")
+

framework/MatrixStack.cpp

 #include <glloader/gl_3_2_comp.h>
 #include "framework.h"
 #include "MatrixStack.h"
-
-
+#include <glm/gtc/matrix_projection.hpp>
 
 namespace Framework
 {
 
 	void MatrixStack::Perspective( float fDegFOV, float fAspectRatio, float fZNear, float fZFar )
 	{
-		glm::mat4 persMat(0.0f);
-
-		const float degToRad = 3.14159f * 2.0f / 360.0f;
-		float fFovRad = fDegFOV * degToRad;
-		float fFrustumScale = 1.0f / tan(fFovRad / 2.0f);
-
-		persMat[0].x = fFrustumScale * fAspectRatio;
-		persMat[1].y = fFrustumScale;
-		persMat[2].z = (fZFar + fZNear) / (fZNear - fZFar);
-		persMat[2].w = -1.0f;
-		persMat[3].z = (2 * fZFar * fZNear) / (fZNear - fZFar);
-
-		m_currMat *= persMat;
+		m_currMat *= glm::perspective(fDegFOV, 1.0f / fAspectRatio, fZNear, fZFar);
 	}
 
 	void MatrixStack::SetMatrix( const glm::mat4 &theMatrix )

framework/Timer.cpp

 		switch(m_eType)
 		{
 		case TT_LOOP:
-			return fmodf(m_fAccumTime, m_fDuration);
+			return fmodf(m_fAccumTime, m_fDuration) / m_fDuration;
 		case TT_SINGLE:
 			return glm::clamp(m_fAccumTime / m_fDuration, 0.0f, 1.0f);
 		}

framework/Timer.h

 		through a loop, or the time in seconds until the timer expires.
 
 		INFINITE timers ignore the duration.
+
+		It is legal to create these statically.
 		**/
 		Timer(Type eType = TT_INFINITE, float fDuration = 1.0f);