Commits

Jason McKesson committed 2463b59

Finished directional diffuse lighting code.

Comments (0)

Files changed (12)

Documents/Illumination/Tutorial 08.xml

             our iris and lenses use a number of photorecepters (light-sensitive cells) to resolve a
             pair of images. The light we see can have one of two sources. A light emitting object
             like the sun or a lamp can emit light that is directly captured by our eyes. Or a
-            surface can reflect light from another source that is captured by our eyes.</para>
+            surface can reflect light from another source that is captured by our eyes. Light
+            emitting objects are called <glossterm>light sources.</glossterm></para>
         <para>The interaction between a light and a surface is the most important part of a lighting
             model. It is also the most difficult to get right. The way light interacts with atoms on
             a surface alone involves complicated quantum mechanics to understand. And even that does
         <para>The very first approximation that is made is that not all of these wavelengths matter.
             Instead of tracking millions of wavelengths in the visible spectrum, we will instead
             track 3. Red, green, and blue.</para>
-        <para>So, we know that the RGB color of the light from a surface is a combination of
-            absorbing characteristics of the surface and the color and intensity of the light. We
-            can describe both the light color and the absorbing characteristics of the surface as
-            RGB colors.</para>
-        <para>But the intensity of light reflected from a surface depends on more than just the
-            color and intensity of the light emitted from the light and the surface color. It also
-            depends on the angle between the light and the surface.</para>
+        <para>The RGB intensity of light reflected from a surface at a particular point is a
+            combination of the RGB light absorbing characteristics of the surface at that point and
+            the RGB <glossterm>light intensity</glossterm> shone on that point on the surface. All
+            of these, the reflected light, the source light, and the surface absorption, can be
+            described as RGB colors, on the range [0, 1].</para>
+        <para>The intensity of light shone upon a surface depends on (at least) two things. First,
+            it depends on the intensity of light that the light source in question emits. And
+            second, it depends on the angle between the surface and the light.</para>
         <para>Consider a perfectly flat surface. If you shine a column of light with a known
             intensity directly onto that surface, the intensity of that light at each point under
             the surface will be a known value, based on the intensity of the light divided by the
             area projected on the surface.</para>
         <!--TODO: Show a column of light shining directly onto the surface.-->
         <para>If the light is shone instead at an angle, the area on the surface is much wider. This
-            spreads the light intensity over a larger area of the surface, so each point under the
-            light sees the light less intensely.</para>
+            spreads the same light intensity over a larger area of the surface; as a result, each
+            point under the light <quote>sees</quote> the light less intensely.</para>
         <!--TODO: Show a column of light shining at an angle to the surface.-->
-        <para>Therefore, the intensity of the light on a surface is a function of the original
-            light's intensity and the angle between the surface and the light source. This angle is
-            called the <glossterm>angle of incidence</glossterm> of the light.</para>
-        <para>A lighting model is a function of all of these parameters. Complex lighting models can
-            add additional parameters.</para>
+        <para>Therefore, the intensity of the light cast upon a surface is a function of the
+            original light's intensity and the angle between the surface and the light source. This
+            angle is called the <glossterm>angle of incidence</glossterm> of the light.</para>
+        <para>A lighting model is a function of all of these parameters. This is far from a
+            comprehensive list of lighting parameters; this list will be expanded considerably in
+            future discussions.</para>
         <section>
             <title>Standard Diffuse Lighting</title>
             <para>The most common lighting model in use is <glossterm>diffuse lighting</glossterm>.
                 direction is called the <glossterm>surface normal</glossterm> or
                     <glossterm>normal.</glossterm> It is the direction that the surface is facing at
                 the location of interest.</para>
-            <para>Every point along a triangle has the same geometric surface normal. That's all
-                well and good.</para>
-            <para>But polygonal models are supposed to be approximations of real, curved surfaces.
-                If we use the actual triangle's surface normal for all of the points on a triangle,
-                the object would look very faceted. This would certainly be an accurate
-                representation of the actual triangular mesh, but it reveals the surface to be
-                exactly what it is: a triangular mesh approximation of a curved surface. If we want
-                to create the illusion that the surface really is curved, we need to do something
-                else.</para>
+            <para>Every point along the surface of a single triangle has the same geometric surface
+                normal. That's all well and good, for actual triangles. But polygonal models are
+                usually supposed to be approximations of real, curved surfaces. If we use the actual
+                triangle's surface normal for all of the points on a triangle, the object would look
+                very faceted. This would certainly be an accurate representation of the actual
+                triangular mesh, but it reveals the surface to be exactly what it is: a triangular
+                mesh approximation of a curved surface. If we want to create the illusion that the
+                surface really is curved, we need to do something else.</para>
             <para>Instead of using the triangle's normal, we can assign to each vertex the normal
-                that it <emphasis>would</emphasis> have on the surface it is approximating. That is,
-                while the mesh is an approximating, the normal for a vertex is the actual normal for
-                that surface. This actually works out surprisingly well.</para>
+                that it <emphasis>would</emphasis> have had on the surface it is approximating. That
+                is, while the mesh is an approximating, the normal for a vertex is the actual normal
+                for that surface. This actually works out surprisingly well.</para>
             <para>This means that we must add to the vertex's information. In past tutorials, we
                 have had a position and sometimes a color. To that information, we add a normal. So
                 we will need a vertex attribute that represents the normal.</para>
         <section>
             <title>Gouraud Shading</title>
             <para>So each vertex has a normal. That is useful, but it is not sufficient, for one
-                simple reason. We don't draw the vertices of triangles; we draw the rasterized form
-                that makes up the interior of a triangle.</para>
+                simple reason. We don't draw the vertices of triangles; we draw the interior of a
+                triangle through rasterization.</para>
             <para>There are several ways to go about computing lighting across the surface of a
                 triangle. The simplest to code, and most efficient for rendering, is to perform the
                 lighting computations at every vertex, and then let the result of this computation
             <para>Direction light sources are a good model for lights like the sun relative to a
                 small region of the Earth. It would not be a good model for the sun relative to the
                 rest of the solar system. So scale is important.</para>
+            <para>Light sources do not have to be physical objects rendered in the scene. All we
+                need to use a directional light is to provide a direction to our lighting model when
+                rendering the surface we want to see. However, having light appear from seemingly
+                nothing hurts verisimilitude; this should be avoided where possible.</para>
             <para>Alternatives to directional lights will be discussed a bit later.</para>
         </section>
     </section>
                 </glossdef>
             </glossentry>
             <glossentry>
+                <glossterm>light source</glossterm>
+                <glossdef>
+                    <para/>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>light intensity</glossterm>
+                <glossdef>
+                    <para>The intensity, measured in RGB, of light emitted from a light-casting
+                        source.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
                 <glossterm>angle of incidence</glossterm>
                 <glossdef>
                     <para/>

Documents/Positioning/Tutorial 07.xml

             </mediaobject>
         </figure>
         <para>The controls for this tutorial are as follows:</para>
-        <!--TODO: Add the table of key controls.-->
         <table frame="all">
             <title>World Space Controls</title>
             <tgroup cols="3">

Tut 08 Lights on/Basic Lighting.cpp

 struct ProgramData
 {
 	GLuint theProgram;
-	GLuint modelToWorldMatrixUnif;
-	GLuint worldToCameraMatrixUnif;
+
+	GLuint dirToLightUnif;
+	GLuint lightIntensityUnif;
+
 	GLuint cameraToClipMatrixUnif;
-	GLuint baseColorUnif;
+	GLuint modelToCameraMatrixUnif;
+	GLuint normalModelToCameraMatrixUnif;
 };
 
 float g_fzNear = 1.0f;
 float g_fzFar = 1000.0f;
 
-ProgramData UniformColor;
-ProgramData ObjectColor;
-ProgramData UniformColorTint;
+ProgramData g_WhiteDiffuseColor;
+ProgramData g_VertexDiffuseColor;
 
 ProgramData LoadProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
 {
 
 	ProgramData data;
 	data.theProgram = Framework::CreateProgram(shaderList);
-	data.modelToWorldMatrixUnif = glGetUniformLocation(data.theProgram, "modelToWorldMatrix");
-	data.worldToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "worldToCameraMatrix");
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
 	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
-	data.baseColorUnif = glGetUniformLocation(data.theProgram, "baseColor");
+	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
+	data.dirToLightUnif = glGetUniformLocation(data.theProgram, "dirToLight");
+	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
 
 	return data;
 }
 
 void InitializeProgram()
 {
-	UniformColor = LoadProgram("PosOnlyWorldTransform.vert", "ColorUniform.frag");
-	ObjectColor = LoadProgram("PosColorWorldTransform.vert", "ColorPassthrough.frag");
-	UniformColorTint = LoadProgram("PosColorWorldTransform.vert", "ColorMultUniform.frag");
+	g_WhiteDiffuseColor = LoadProgram("DirVertexLighting_PN.vert", "ColorPassthrough.frag");
+	g_VertexDiffuseColor = LoadProgram("DirVertexLighting_PCN.vert", "ColorPassthrough.frag");
 }
 
 glm::mat4 CalcLookAtMatrix(const glm::vec3 &cameraPt, const glm::vec3 &lookPt, const glm::vec3 &upPt)
 	return rotMat * transMat;
 }
 
-Framework::Mesh *g_pConeMesh = NULL;
 Framework::Mesh *g_pCylinderMesh = NULL;
-Framework::Mesh *g_pCubeTintMesh = NULL;
-Framework::Mesh *g_pCubeColorMesh = NULL;
 Framework::Mesh *g_pPlaneMesh = NULL;
 
 //Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
 
 	try
 	{
-		g_pConeMesh = new Framework::Mesh("UnitConeTint.xml");
-		g_pCylinderMesh = new Framework::Mesh("UnitCylinderTint.xml");
-		g_pCubeTintMesh = new Framework::Mesh("UnitCubeTint.xml");
-		g_pCubeColorMesh = new Framework::Mesh("UnitCubeColor.xml");
-		g_pPlaneMesh = new Framework::Mesh("UnitPlane.xml");
+//		g_pConeMesh = new Framework::Mesh("UnitConeTint.xml");
+//		g_pCubeTintMesh = new Framework::Mesh("UnitCubeTint.xml");
+//		g_pCubeColorMesh = new Framework::Mesh("UnitCubeColor.xml");
+		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
+		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
 	}
 	catch(std::exception &except)
 	{
 	glEnable(GL_DEPTH_CLAMP);
 }
 
-static float g_fYAngle = 0.0f;
-static float g_fXAngle = 0.0f;
-
-//Trees are 3x3 in X/Z, and fTrunkHeight+fConeHeight in the Y.
-void DrawTree(Framework::MatrixStack &modelMatrix, float fTrunkHeight = 2.0f, float fConeHeight = 3.0f)
-{
-	//Draw trunk.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Scale(glm::vec3(1.0f, fTrunkHeight, 1.0f));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.694f, 0.4f, 0.106f, 1.0f);
-		g_pCylinderMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw the treetop
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(0.0f, fTrunkHeight, 0.0f));
-		modelMatrix.Scale(glm::vec3(3.0f, fConeHeight, 3.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.0f, 1.0f, 0.0f, 1.0f);
-		g_pConeMesh->Render();
-		glUseProgram(0);
-	}
-}
-
-const float g_fColumnBaseHeight = 0.25f;
-
-//Columns are 1x1 in the X/Z, and fHieght units in the Y.
-void DrawColumn(Framework::MatrixStack &modelMatrix, float fHeight = 5.0f)
-{
-	//Draw the bottom of the column.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Scale(glm::vec3(1.0f, g_fColumnBaseHeight, 1.0f));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
-		g_pCubeTintMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw the top of the column.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(0.0f, fHeight - g_fColumnBaseHeight, 0.0f));
-		modelMatrix.Scale(glm::vec3(1.0f, g_fColumnBaseHeight, 1.0f));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
-		g_pCubeTintMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw the main column.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(0.0f, g_fColumnBaseHeight, 0.0f));
-		modelMatrix.Scale(glm::vec3(0.8f, fHeight - (g_fColumnBaseHeight * 2.0f), 0.8f));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
-		g_pCylinderMesh->Render();
-		glUseProgram(0);
-	}
-}
-
-const float g_fParthenonWidth = 14.0f;
-const float g_fParthenonLength = 20.0f;
-const float g_fParthenonColumnHeight = 5.0f;
-const float g_fParthenonBaseHeight = 1.0f;
-const float g_fParthenonTopHeight = 2.0f;
-
-void DrawParthenon(Framework::MatrixStack &modelMatrix)
-{
-	//Draw base.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Scale(glm::vec3(g_fParthenonWidth, g_fParthenonBaseHeight, g_fParthenonLength));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
-		g_pCubeTintMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw top.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(0.0f, g_fParthenonColumnHeight + g_fParthenonBaseHeight, 0.0f));
-		modelMatrix.Scale(glm::vec3(g_fParthenonWidth, g_fParthenonTopHeight, g_fParthenonLength));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		glUniform4f(UniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
-		g_pCubeTintMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw columns.
-	const float fFrontZVal = (g_fParthenonLength / 2.0f) - 1.0f;
-	const float fRightXVal = (g_fParthenonWidth / 2.0f) - 1.0f;
-
-	for(int iColumnNum = 0; iColumnNum < int(g_fParthenonWidth / 2.0f); iColumnNum++)
-	{
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-			modelMatrix.Translate(glm::vec3((2.0f * iColumnNum) - (g_fParthenonWidth / 2.0f) + 1.0f,
-				g_fParthenonBaseHeight, fFrontZVal));
-
-			DrawColumn(modelMatrix, g_fParthenonColumnHeight);
-		}
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-			modelMatrix.Translate(glm::vec3((2.0f * iColumnNum) - (g_fParthenonWidth / 2.0f) + 1.0f,
-				g_fParthenonBaseHeight, -fFrontZVal));
-
-			DrawColumn(modelMatrix, g_fParthenonColumnHeight);
-		}
-	}
-
-	//Don't draw the first or last columns, since they've been drawn already.
-	for(int iColumnNum = 1; iColumnNum < int((g_fParthenonLength - 2.0f) / 2.0f); iColumnNum++)
-	{
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-			modelMatrix.Translate(glm::vec3(fRightXVal,
-				g_fParthenonBaseHeight, (2.0f * iColumnNum) - (g_fParthenonLength / 2.0f) + 1.0f));
-
-			DrawColumn(modelMatrix, g_fParthenonColumnHeight);
-		}
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-			modelMatrix.Translate(glm::vec3(-fRightXVal,
-				g_fParthenonBaseHeight, (2.0f * iColumnNum) - (g_fParthenonLength / 2.0f) + 1.0f));
-
-			DrawColumn(modelMatrix, g_fParthenonColumnHeight);
-		}
-	}
-
-	//Draw interior.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(0.0f, 1.0f, 0.0f));
-		modelMatrix.Scale(glm::vec3(g_fParthenonWidth - 6.0f, g_fParthenonColumnHeight,
-			g_fParthenonLength - 6.0f));
-		modelMatrix.Translate(glm::vec3(0.0f, 0.5f, 0.0f));
-
-		glUseProgram(ObjectColor.theProgram);
-		glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		g_pCubeColorMesh->Render();
-		glUseProgram(0);
-	}
-
-	//Draw headpiece.
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-
-		modelMatrix.Translate(glm::vec3(
-			0.0f,
-			g_fParthenonColumnHeight + g_fParthenonBaseHeight + (g_fParthenonTopHeight / 2.0f),
-			g_fParthenonLength / 2.0f));
-		modelMatrix.RotateX(-135.0f);
-		modelMatrix.RotateY(45.0f);
-
-		glUseProgram(ObjectColor.theProgram);
-		glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-		g_pCubeColorMesh->Render();
-		glUseProgram(0);
-	}
-}
-
-struct TreeData
-{
-	float fXPos;
-	float fZPos;
-	float fTrunkHeight;
-	float fConeHeight;
-};
-
-static const TreeData g_forest[] =
-{
-	{-45.0f, -40.0f, 2.0f, 3.0f},
-	{-42.0f, -35.0f, 2.0f, 3.0f},
-	{-39.0f, -29.0f, 2.0f, 4.0f},
-	{-44.0f, -26.0f, 3.0f, 3.0f},
-	{-40.0f, -22.0f, 2.0f, 4.0f},
-	{-36.0f, -15.0f, 3.0f, 3.0f},
-	{-41.0f, -11.0f, 2.0f, 3.0f},
-	{-37.0f, -6.0f, 3.0f, 3.0f},
-	{-45.0f, 0.0f, 2.0f, 3.0f},
-	{-39.0f, 4.0f, 3.0f, 4.0f},
-	{-36.0f, 8.0f, 2.0f, 3.0f},
-	{-44.0f, 13.0f, 3.0f, 3.0f},
-	{-42.0f, 17.0f, 2.0f, 3.0f},
-	{-38.0f, 23.0f, 3.0f, 4.0f},
-	{-41.0f, 27.0f, 2.0f, 3.0f},
-	{-39.0f, 32.0f, 3.0f, 3.0f},
-	{-44.0f, 37.0f, 3.0f, 4.0f},
-	{-36.0f, 42.0f, 2.0f, 3.0f},
-
-	{-32.0f, -45.0f, 2.0f, 3.0f},
-	{-30.0f, -42.0f, 2.0f, 4.0f},
-	{-34.0f, -38.0f, 3.0f, 5.0f},
-	{-33.0f, -35.0f, 3.0f, 4.0f},
-	{-29.0f, -28.0f, 2.0f, 3.0f},
-	{-26.0f, -25.0f, 3.0f, 5.0f},
-	{-35.0f, -21.0f, 3.0f, 4.0f},
-	{-31.0f, -17.0f, 3.0f, 3.0f},
-	{-28.0f, -12.0f, 2.0f, 4.0f},
-	{-29.0f, -7.0f, 3.0f, 3.0f},
-	{-26.0f, -1.0f, 2.0f, 4.0f},
-	{-32.0f, 6.0f, 2.0f, 3.0f},
-	{-30.0f, 10.0f, 3.0f, 5.0f},
-	{-33.0f, 14.0f, 2.0f, 4.0f},
-	{-35.0f, 19.0f, 3.0f, 4.0f},
-	{-28.0f, 22.0f, 2.0f, 3.0f},
-	{-33.0f, 26.0f, 3.0f, 3.0f},
-	{-29.0f, 31.0f, 3.0f, 4.0f},
-	{-32.0f, 38.0f, 2.0f, 3.0f},
-	{-27.0f, 41.0f, 3.0f, 4.0f},
-	{-31.0f, 45.0f, 2.0f, 4.0f},
-	{-28.0f, 48.0f, 3.0f, 5.0f},
-
-	{-25.0f, -48.0f, 2.0f, 3.0f},
-	{-20.0f, -42.0f, 3.0f, 4.0f},
-	{-22.0f, -39.0f, 2.0f, 3.0f},
-	{-19.0f, -34.0f, 2.0f, 3.0f},
-	{-23.0f, -30.0f, 3.0f, 4.0f},
-	{-24.0f, -24.0f, 2.0f, 3.0f},
-	{-16.0f, -21.0f, 2.0f, 3.0f},
-	{-17.0f, -17.0f, 3.0f, 3.0f},
-	{-25.0f, -13.0f, 2.0f, 4.0f},
-	{-23.0f, -8.0f, 2.0f, 3.0f},
-	{-17.0f, -2.0f, 3.0f, 3.0f},
-	{-16.0f, 1.0f, 2.0f, 3.0f},
-	{-19.0f, 4.0f, 3.0f, 3.0f},
-	{-22.0f, 8.0f, 2.0f, 4.0f},
-	{-21.0f, 14.0f, 2.0f, 3.0f},
-	{-16.0f, 19.0f, 2.0f, 3.0f},
-	{-23.0f, 24.0f, 3.0f, 3.0f},
-	{-18.0f, 28.0f, 2.0f, 4.0f},
-	{-24.0f, 31.0f, 2.0f, 3.0f},
-	{-20.0f, 36.0f, 2.0f, 3.0f},
-	{-22.0f, 41.0f, 3.0f, 3.0f},
-	{-21.0f, 45.0f, 2.0f, 3.0f},
-
-	{-12.0f, -40.0f, 2.0f, 4.0f},
-	{-11.0f, -35.0f, 3.0f, 3.0f},
-	{-10.0f, -29.0f, 1.0f, 3.0f},
-	{-9.0f, -26.0f, 2.0f, 2.0f},
-	{-6.0f, -22.0f, 2.0f, 3.0f},
-	{-15.0f, -15.0f, 1.0f, 3.0f},
-	{-8.0f, -11.0f, 2.0f, 3.0f},
-	{-14.0f, -6.0f, 2.0f, 4.0f},
-	{-12.0f, 0.0f, 2.0f, 3.0f},
-	{-7.0f, 4.0f, 2.0f, 2.0f},
-	{-13.0f, 8.0f, 2.0f, 2.0f},
-	{-9.0f, 13.0f, 1.0f, 3.0f},
-	{-13.0f, 17.0f, 3.0f, 4.0f},
-	{-6.0f, 23.0f, 2.0f, 3.0f},
-	{-12.0f, 27.0f, 1.0f, 2.0f},
-	{-8.0f, 32.0f, 2.0f, 3.0f},
-	{-10.0f, 37.0f, 3.0f, 3.0f},
-	{-11.0f, 42.0f, 2.0f, 2.0f},
-
-
-	{15.0f, 5.0f, 2.0f, 3.0f},
-	{15.0f, 10.0f, 2.0f, 3.0f},
-	{15.0f, 15.0f, 2.0f, 3.0f},
-	{15.0f, 20.0f, 2.0f, 3.0f},
-	{15.0f, 25.0f, 2.0f, 3.0f},
-	{15.0f, 30.0f, 2.0f, 3.0f},
-	{15.0f, 35.0f, 2.0f, 3.0f},
-	{15.0f, 40.0f, 2.0f, 3.0f},
-	{15.0f, 45.0f, 2.0f, 3.0f},
-
-	{25.0f, 5.0f, 2.0f, 3.0f},
-	{25.0f, 10.0f, 2.0f, 3.0f},
-	{25.0f, 15.0f, 2.0f, 3.0f},
-	{25.0f, 20.0f, 2.0f, 3.0f},
-	{25.0f, 25.0f, 2.0f, 3.0f},
-	{25.0f, 30.0f, 2.0f, 3.0f},
-	{25.0f, 35.0f, 2.0f, 3.0f},
-	{25.0f, 40.0f, 2.0f, 3.0f},
-	{25.0f, 45.0f, 2.0f, 3.0f},
-};
-
-void DrawForest(Framework::MatrixStack &modelMatrix)
-{
-	for(int iTree = 0; iTree < ARRAY_COUNT(g_forest); iTree++)
-	{
-		const TreeData &currTree = g_forest[iTree];
-
-		Framework::MatrixStackPusher push(modelMatrix);
-		modelMatrix.Translate(glm::vec3(currTree.fXPos, 0.0f, currTree.fZPos));
-		DrawTree(modelMatrix, currTree.fTrunkHeight, currTree.fConeHeight);
-	}
-}
-
-static bool g_bDrawLookatPoint = false;
-static glm::vec3 g_camTarget(0.0f, 0.4f, 0.0f);
+static glm::vec3 g_camTarget(0.0f, 0.5f, 0.0f);
 
 //In spherical coordinates.
-static glm::vec3 g_sphereCamRelPos(67.5f, -46.0f, 150.0f);
+static glm::vec3 g_sphereCamRelPos(67.5f, -46.0f, 5.0f);
 
 glm::vec3 ResolveCamPosition()
 {
-	Framework::MatrixStack tempMat;
-
 	float rho = Framework::DegToRad(g_sphereCamRelPos.x);
 	float theta = Framework::DegToRad(g_sphereCamRelPos.y + 90.0f);
 
 	return (dirToCamera * g_sphereCamRelPos.z) + g_camTarget;
 }
 
+glm::vec4 g_lightDirection(0.866f, 0.5f, 0.0f, 0.0f);
+
+static float g_CylYaw = 0.0f;
+static float g_CylPitch = 0.0f;
+static float g_CylRoll = 0.0f;
+
+static bool g_bDrawColoredCyl = true;
+
 //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.
 	glClearDepth(1.0f);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-	if(g_pConeMesh && g_pCylinderMesh && g_pCubeTintMesh && g_pCubeColorMesh && g_pPlaneMesh)
+	if(g_pPlaneMesh && g_pCylinderMesh)
 	{
 		const glm::vec3 &camPos = ResolveCamPosition();
 
-		Framework::MatrixStack camMatrix;
-		camMatrix.SetMatrix(CalcLookAtMatrix(camPos, g_camTarget, glm::vec3(0.0f, 1.0f, 0.0f)));
+		Framework::MatrixStack modelMatrix;
+		modelMatrix.SetMatrix(CalcLookAtMatrix(camPos, g_camTarget, glm::vec3(0.0f, 1.0f, 0.0f)));
 
-		glUseProgram(UniformColor.theProgram);
-		glUniformMatrix4fv(UniformColor.worldToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(camMatrix.Top()));
-		glUseProgram(ObjectColor.theProgram);
-		glUniformMatrix4fv(ObjectColor.worldToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(camMatrix.Top()));
-		glUseProgram(UniformColorTint.theProgram);
-		glUniformMatrix4fv(UniformColorTint.worldToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(camMatrix.Top()));
+		glm::vec4 lightDirCameraSpace = modelMatrix.Top() * g_lightDirection;
+
+		glUseProgram(g_WhiteDiffuseColor.theProgram);
+		glUniform3fv(g_WhiteDiffuseColor.dirToLightUnif, 1, glm::value_ptr(lightDirCameraSpace));
+		glUseProgram(g_VertexDiffuseColor.theProgram);
+		glUniform3fv(g_VertexDiffuseColor.dirToLightUnif, 1, glm::value_ptr(lightDirCameraSpace));
 		glUseProgram(0);
 
-		Framework::MatrixStack modelMatrix;
-
-		//Render the ground plane.
 		{
 			Framework::MatrixStackPusher push(modelMatrix);
 
-			modelMatrix.Scale(glm::vec3(100.0f, 1.0f, 100.0f));
+			//Render the ground plane.
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
 
-			glUseProgram(UniformColor.theProgram);
-			glUniformMatrix4fv(UniformColor.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-			glUniform4f(UniformColor.baseColorUnif, 0.302f, 0.416f, 0.0589f, 1.0f);
-			g_pPlaneMesh->Render();
-			glUseProgram(0);
-		}
+				glUseProgram(g_WhiteDiffuseColor.theProgram);
+				glUniformMatrix4fv(g_WhiteDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+				glUniformMatrix4fv(g_WhiteDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+				glUniform4f(g_WhiteDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+				g_pPlaneMesh->Render();
+				glUseProgram(0);
+			}
 
-		//Draw the trees
-		DrawForest(modelMatrix);
+			//Render the Cylinder
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
 
-		//Draw the building.
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-			modelMatrix.Translate(glm::vec3(20.0f, 0.0f, -10.0f));
+				modelMatrix.Translate(0.0f, 0.5f, 0.0f);
 
-			DrawParthenon(modelMatrix);
-		}
+				modelMatrix.RotateX(g_CylPitch);
+				modelMatrix.RotateY(g_CylYaw);
+				modelMatrix.RotateZ(g_CylRoll);
 
-		if(g_bDrawLookatPoint)
-		{
-			glDisable(GL_DEPTH_TEST);
-			glm::mat4 idenity(1.0f);
-
-			Framework::MatrixStackPusher push(modelMatrix);
-
-			glm::vec3 cameraAimVec = g_camTarget - camPos;
-			modelMatrix.Translate(0.0f, 0.0, -glm::length(cameraAimVec));
-			modelMatrix.Scale(1.0f, 1.0f, 1.0f);
-		
-			glUseProgram(ObjectColor.theProgram);
-			glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
-			glUniformMatrix4fv(ObjectColor.worldToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(idenity));
-			g_pCubeColorMesh->Render();
-			glUseProgram(0);
-			glEnable(GL_DEPTH_TEST);
+				if(g_bDrawColoredCyl)
+				{
+					glUseProgram(g_VertexDiffuseColor.theProgram);
+					glUniformMatrix4fv(g_VertexDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+					glUniformMatrix4fv(g_VertexDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+					glUniform4f(g_VertexDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+					g_pCylinderMesh->Render("tint");
+				}
+				else
+				{
+					glUseProgram(g_WhiteDiffuseColor.theProgram);
+					glUniformMatrix4fv(g_WhiteDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+					glUniformMatrix4fv(g_WhiteDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top()));
+					glUniform4f(g_WhiteDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+					g_pCylinderMesh->Render("flat");
+				}
+				glUseProgram(0);
+			}
 		}
 	}
 
 	Framework::MatrixStack persMatrix;
 	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
 
-	glUseProgram(UniformColor.theProgram);
-	glUniformMatrix4fv(UniformColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top()));
-	glUseProgram(ObjectColor.theProgram);
-	glUniformMatrix4fv(ObjectColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top()));
-	glUseProgram(UniformColorTint.theProgram);
-	glUniformMatrix4fv(UniformColorTint.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_WhiteDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_WhiteDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_VertexDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_VertexDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top()));
 	glUseProgram(0);
 
 	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
 	switch (key)
 	{
 	case 27:
-		delete g_pConeMesh;
+		delete g_pPlaneMesh;
 		delete g_pCylinderMesh;
-		delete g_pCubeTintMesh;
-		delete g_pCubeColorMesh;
 		glutLeaveMainLoop();
 		break;
-	case 'w': g_camTarget.z -= 4.0f; break;
-	case 's': g_camTarget.z += 4.0f; break;
-	case 'd': g_camTarget.x += 4.0f; break;
-	case 'a': g_camTarget.x -= 4.0f; break;
-	case 'e': g_camTarget.y -= 4.0f; break;
-	case 'q': g_camTarget.y += 4.0f; break;
-	case 'W': g_camTarget.z -= 0.4f; break;
-	case 'S': g_camTarget.z += 0.4f; break;
-	case 'D': g_camTarget.x += 0.4f; break;
-	case 'A': g_camTarget.x -= 0.4f; break;
-	case 'E': g_camTarget.y -= 0.4f; break;
-	case 'Q': g_camTarget.y += 0.4f; break;
+	case 'w': g_CylPitch -= 11.25f; break;
+	case 's': g_CylPitch += 11.25f; break;
+	case 'd': g_CylYaw += 11.25f; break;
+	case 'a': g_CylYaw -= 11.25f; break;
+	case 'e': g_CylRoll -= 11.25f; break;
+	case 'q': g_CylRoll += 11.25f; break;
+	case 'W': g_CylPitch -= 4.0f; break;
+	case 'S': g_CylPitch += 4.0f; break;
+	case 'D': g_CylYaw += 4.0f; break;
+	case 'A': g_CylYaw -= 4.0f; break;
+	case 'E': g_CylRoll -= 4.0f; break;
+	case 'Q': g_CylRoll += 4.0f; break;
 	case 'i': g_sphereCamRelPos.y -= 11.25f; break;
 	case 'k': g_sphereCamRelPos.y += 11.25f; break;
 	case 'j': g_sphereCamRelPos.x -= 11.25f; break;
 	case 'l': g_sphereCamRelPos.x += 11.25f; break;
-	case 'o': g_sphereCamRelPos.z -= 5.0f; break;
-	case 'u': g_sphereCamRelPos.z += 5.0f; break;
+	case 'o': g_sphereCamRelPos.z -= 1.5f; break;
+	case 'u': g_sphereCamRelPos.z += 1.5f; break;
 	case 'I': g_sphereCamRelPos.y -= 1.125f; break;
 	case 'K': g_sphereCamRelPos.y += 1.125f; break;
 	case 'J': g_sphereCamRelPos.x -= 1.125f; break;
 	case 'L': g_sphereCamRelPos.x += 1.125f; break;
-	case 'O': g_sphereCamRelPos.z -= 0.5f; break;
-	case 'U': g_sphereCamRelPos.z += 0.5f; break;
+	case 'O': g_sphereCamRelPos.z -= 0.25f; break;
+	case 'U': g_sphereCamRelPos.z += 0.25f; break;
 		
 	case 32:
-		g_bDrawLookatPoint = !g_bDrawLookatPoint;
-		printf("Target: %f, %f, %f\n", g_camTarget.x, g_camTarget.y, g_camTarget.z);
+		g_bDrawColoredCyl = !g_bDrawColoredCyl;
 		printf("Position: %f, %f, %f\n", g_sphereCamRelPos.x, g_sphereCamRelPos.y, g_sphereCamRelPos.z);
+		printf("Yaw: %f, Pitch: %f, Roll: %f\n", g_CylYaw, g_CylPitch, g_CylRoll);
 		break;
 	}
 
-	g_sphereCamRelPos.y = glm::clamp(g_sphereCamRelPos.y, -78.75f, -1.0f);
+	g_sphereCamRelPos.y = glm::clamp(g_sphereCamRelPos.y, -78.75f, 78.75f);
 	g_camTarget.y = g_camTarget.y > 0.0f ? g_camTarget.y : 0.0f;
-	g_sphereCamRelPos.z = g_sphereCamRelPos.z > 5.0f ? g_sphereCamRelPos.z : 5.0f;
+	g_sphereCamRelPos.z = g_sphereCamRelPos.z > 2.0f ? g_sphereCamRelPos.z : 2.0f;
 
 	glutPostRedisplay();
 }

Tut 08 Lights on/data/DirVertexLighting_PCN.vert

 #version 330
 
-layout(location = 0) in vec4 position;
+layout(location = 0) in vec3 position;
 layout(location = 1) in vec4 diffuseColor;
 layout(location = 2) in vec3 normal;
 
 
 void main()
 {
-	vec4 temp = modelToWorldMatrix * position;
-	temp = worldToCameraMatrix * temp;
-	gl_Position = cameraToClipMatrix * temp;
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
 
-	vec4 normCamSpace = normalModelToCameraMatrix * vec4(normal, 0.0);
+	vec3 normCamSpace = (normalModelToCameraMatrix * vec4(normal, 0.0)).xyz;
 	
 	float cosAngIncidence = dot(normCamSpace, dirToLight);
 	cosAngIncidence = clamp(cosAngIncidence, 0, 1);

Tut 08 Lights on/data/DirVertexLighting_PN.vert

+#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 2) in vec3 normal;
+
+smooth out vec4 interpColor;
+
+uniform vec3 dirToLight;
+uniform vec4 lightIntensity;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+uniform mat4 normalModelToCameraMatrix;
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
+
+	vec3 normCamSpace = (normalModelToCameraMatrix * vec4(normal, 0.0)).xyz;
+	
+	float cosAngIncidence = dot(normCamSpace, dirToLight);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	interpColor = lightIntensity * cosAngIncidence;
+}

Tut 08 Lights on/data/GenCylinder.lua

 
 local positions = {};
 local colors = {};
+local normals = {};
 local topFan = {};
 local botFan = {};
 local cylStrip = {};
 local highColor = vmath.vec4(0.9, 0.9, 0.9, 1.0);
 local lowColor = vmath.vec4(0.5, 0.5, 0.5, 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));
 
+	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;
 
 	topFan[#topFan + 1] = 1 + (iSeg * 2);
 	botFan[#botFan + 1] = 1 + (((iSegCount - iSeg) * 2) - 1);
-	cylStrip[#cylStrip + 1] = 1 + (iSeg * 2);
-	cylStrip[#cylStrip + 1] = 1 + (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];
 
-positions[#positions + 1] = vmath.vec3(0.0, -0.5, 0.0);
-colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
-
-
 do
-	local writer = XmlWriter.XmlWriter("UnitCylinderTint.xml");
+	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("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:PopElement();
 	writer:Close();
 end
-
-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("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 08 Lights on/data/GenPlane.lua

 	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(3.0, 0.0, -3.0),
+	vmath.vec3(3.0, 0.0, 3.0),
+	vmath.vec3(-3.0, 0.0, 3.0),
+	vmath.vec3(-3.0, 0.0, -3.0),
+
+	vmath.vec3(3.0, 0.0, -3.0),
+	vmath.vec3(3.0, 0.0, 3.0),
+	vmath.vec3(-3.0, 0.0, 3.0),
+	vmath.vec3(-3.0, 0.0, -3.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(0, 2, 1),
 	vmath.vec3(2, 3, 0),
-	vmath.vec3(2, 0, 3),
+
+	vmath.vec3(4, 6, 5),
+	vmath.vec3(6, 4, 7),
 };
 
 do
 			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: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 08 Lights on/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" > 
+        3 0 -3
+        3 0 3
+        -3 0 3
+        -3 0 -3
+        3 0 -3
+        3 0 3
+        -3 0 3
+        -3 0 -3</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 08 Lights on/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.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        1 1 1 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.58 0.58 0.58 1
+        0.58 0.58 0.58 1
+        0.66 0.66 0.66 1
+        0.66 0.66 0.66 1
+        0.74 0.74 0.74 1
+        0.74 0.74 0.74 1
+        0.82 0.82 0.82 1
+        0.82 0.82 0.82 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 08 Lights on/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>

framework/framework.cpp

 
 namespace Framework
 {
-	GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile)
+	GLuint CreateShader(GLenum eShaderType,
+		const std::string &strShaderFile, const std::string &strShaderName)
 	{
 		GLuint shader = glCreateShader(eShaderType);
 		const char *strFileData = strShaderFile.c_str();
 			case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
 			}
 
-			fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
+			fprintf(stderr, "Compile failure in %s shader named \"%s\". Error:\n%s\n",
+				strShaderType, strShaderName.c_str(), strInfoLog);
 			delete[] strInfoLog;
 		}
 
 		shaderData << shaderFile.rdbuf();
 		shaderFile.close();
 
-		return CreateShader(eShaderType, shaderData.str());
+		return CreateShader(eShaderType, shaderData.str(), strShaderFilename);
 	}
 
 	GLuint CreateProgram(const std::vector<GLuint> &shaderList)

framework/framework.h

 {
 	float DegToRad(float fAngDeg);
 
-	GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile);
+	GLuint CreateShader(GLenum eShaderType,
+		const std::string &strShaderFile, const std::string &strShaderName);
 	GLuint LoadShader(GLenum eShaderType, const std::string &strShaderFilename);
 	GLuint CreateProgram(const std::vector<GLuint> &shaderList);