Commits

Jason McKesson committed 8343d52

Started Tutorial 09 writeup.
Also moved the perspective correction to Tut 12.

  • Participants
  • Parent commits d4d0025

Comments (0)

Files changed (25)

File Documents/Illumination/Tutorial 09.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng" type="xml"?>
+<?oxygen SCHSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng"?>
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude"
+    xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
+    <?dbhtml filename="Tutorial 09.html" ?>
+    <title>Plane Lights</title>
+    <para>Directional lights are useful for representing light sources like the sun and so forth.
+        But most light sources are more likely to be represented as point lights.</para>
+    <para>A <glossterm>point light</glossterm> is a light source that has a position in the world
+        and shines with equal intensity in all directions. Our simple diffuse lighting equation is a
+        function of these properties:</para>
+    <itemizedlist>
+        <listitem>
+            <para>The surface normal at that point.</para>
+        </listitem>
+        <listitem>
+            <para>The direction from the point on the surface to the light.</para>
+        </listitem>
+    </itemizedlist>
+    <para>The direction to the light source from the point is a constant when dealing with
+        directional light. It is a parameter for lighting, but it is a constant value for all points
+        in the scene. The difference between directional lighting and point lights is only that this
+        direction must be computed for each position in the scene.</para>
+    <para>Computing this is quite simple. At the point of interest, we take the difference between
+        the point on the surface and the light's position. We normalize the result to produce a unit
+        vector direction to the light. Then we use the light direction as we did before. The surface
+        point, light position, and surface normal must all be in the same space for this equation to
+        make sense.</para>
+    <section>
+        <title>Vertex Point Lighting</title>
+        <para>Thus far, we have computed the lighting equation at each vertex and interpolated the
+            results across the surface of the triangle. We will continue to do so for point lights.
+            For the moment, at least.</para>
+        <para>We implement point lights per-vertex in the <phrase role="propername">Vertex Point
+                Lighting</phrase> tutorial. This tutorial has a moving point light that circles
+            around the cylinder.</para>
+        <!--TODO: Show a picture of the tutorial.-->
+        <para>It controls as follows:</para>
+        <!--TODO: Have a table explaining the tutorial's controls.-->
+        <para>Most of the code is nothing we haven't seen elsewhere. The main changes are at the top
+            of the rendering function.</para>
+        <example>
+            <title>Per-Vertex Point Light Rendering</title>
+            <programlisting language="cpp">Framework::MatrixStack modelMatrix;
+modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
+
+const glm::vec4 &amp;worldLightPos = CalcLightPosition();
+
+glm::vec4 lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
+
+glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
+glUniform3fv(g_WhiteAmbDiffuseColor.lightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
+glUseProgram(g_VertexAmbDiffuseColor.theProgram);
+glUniform3fv(g_VertexAmbDiffuseColor.lightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));</programlisting>
+        </example>
+        <para>The light is computed initially in world space, then transformed into camera space.
+            The camera-space light position is given to both of the shaders. Rendering proceeds
+            normally from there.</para>
+        <para>Our vertex shader has had a few changes:</para>
+        <example>
+            <title>Per-Vertex Point Light Vertex Shader</title>
+            <programlisting>#version 330
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec4 diffuseColor;
+layout(location = 2) in vec3 normal;
+
+smooth out vec4 interpColor;
+
+uniform vec3 lightPos;
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+uniform mat3 normalModelToCameraMatrix;
+
+void main()
+{
+    vec4 cameraPosition = (modelToCameraMatrix * vec4(position, 1.0));
+    gl_Position = cameraToClipMatrix * cameraPosition;
+    
+    vec3 normCamSpace = normalize(normalModelToCameraMatrix * normal);
+    
+    vec3 dirToLight = normalize(lightPos - vec3(cameraPosition));
+    
+    float cosAngIncidence = dot(normCamSpace, dirToLight);
+    cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+    
+    interpColor = (diffuseColor * lightIntensity * cosAngIncidence) +
+        (diffuseColor * ambientIntensity);
+}</programlisting>
+        </example>
+        <para>The vertex shader takes a camera-space light position instead of a camera-space light
+            direction. It also stores the camera-space vertex position in a temporary in the first
+            line of <function>main</function>. This is used to compute the direction to the light.
+            From there, the computation proceeds normally.</para>
+        <para>Note the order of operations in computing <varname>dirToLight.</varname> The
+                <varname>lightPos</varname> is on the left and the <varname>cameraPosition</varname>
+            is on the right. Geometrically, this is correct. If you have two points, and you want to
+            find the direction from point A to point B, you compute B - A. The
+                <function>normalize</function> call is just to convert it into a unit vector.</para>
+    </section>
+    <section>
+        <title>Interpolation</title>
+        <para>As you can see, doing point lighting is quite simple. Unfortunately, the visual
+            results are not.</para>
+        <para>For example, use the controls to display the position of the point light source, then
+            position it near the ground plane. See anything wrong?</para>
+        <para>If everything were working correctly, one would expect to see a bright area directly
+            under the light. After all, geometrically, this situation looks like this:</para>
+        <!--TODO: Show a 2D diagram of a point light near a line surface.-->
+        <para>The area directly under the point should be very bright, but the area farther from the
+            point light should be darker. What we see is nothing of the sort. There is no bright
+            light directly under the light source. Why is that?</para>
+        <para>Well, consider what we are doing. We are computing the lighting at every triangle's
+                <emphasis>vertex</emphasis>, and then interpolating the results across the surface
+            of the triangle. The ground plane is made up of precisely four vertices: the four
+            corners. And those are all very far from the light position. Since none of the vertices
+            are close to the light, none of the colors that are interpolated across the surface are
+            bright.</para>
+        <para>You can see this is evident by putting the light position next to the cylinder. If the
+            light is at the top or bottom of the cylinder, then the area near the light will be
+            bright. But if you move the light to the middle of the cylinder, far the top or bottom
+            vertices, then the illumination will be much dimmer.</para>
+        <!--TODO: Show this tutorial with the light at the middle of the cylinder.-->
+        <para>This is not the only problem with doing per-vertex lighting. For example, run the
+            tutorial again and don't move the light. Just watch how the light behaves on the
+            cylinder's surface as it animates around. Unlike with directional lighting, you can very
+            easily see the triangles on the cylinder's surface. This has issues for similar reasons,
+            but it also introduces a new problem: interpolation artifacts.</para>
+        <para>If you move the light source farther away, you can see that the triangles smooth out.
+            But this is simply because, if the light source is far enough away, the results are
+            indistinguishable from a directional light. Each vertex's direction to the light is
+            almost the same as each other vertex's direction to the light.</para>
+        <para>Per-vertex lighting was reasonable when dealing with directional lights. But it simply
+            is not a good idea for point lighting. The question arises: why was per-vertex lighting
+            good with directional lights to begin with?</para>
+        <para>Remember that our diffuse lighting equation has two parameters: the direction to the
+            light and the surface normal. In directional lighting, the direction to the light is
+            always the same. Therefore, the only value that changes over a triangle's surface is the
+            surface normal.</para>
+        <para>The more physically correct method of lighting is to perform lighting at every
+            rendered pixel. To do that, we would have to interpolate the lighting parameters across
+            the triangle, and perform the lighting computation in the fragment shader.</para>
+        <para>Linear interpolation of vectors looks like this:</para>
+        <!--TODO: equation: Va& + Va(1-&)-->
+        <para>And our lighting equation is this:</para>
+        <!--TODO: eq: D * I * dot(L, N)-->
+        <para>If the surface normal N is being interpolated, then at any particular point on the
+            surface, we get this equation:</para>
+        <!--TODO: D * I * dot(L, Na& + Nb(1-&))-->
+        <para>The dot product is distributive, like scalar multiplication. So we can distribute the
+            L to both sides of the dot product term:</para>
+        <!--TODO: D * I * (dot(L, Na&) + dot(L, Nb(1-&)))-->
+        <para>We can extract the linear terms from the dot product. Remember that the dot product is
+            the cosine of the angle between two vectors, times the length of those vectors. The two
+            scaling terms directly modify the length of the vectors. So they can be pulled out to
+            give us:</para>
+        <!--TODO: D * I * (&dot(L, Na) + (1-&)dot(L, Nb))-->
+        <para>Vector multiplication happens to be distributive as well, so we get this:</para>
+        <!--TODO: (D * I * &dot(L, Na)) + (D * I * (1-&)dot(L, Nb))-->
+        <para>Or, rewritten to make things more clear:</para>
+        <!--TODO: (D * I * dot(L, Na))& + (D * I * dot(L, Nb))(1-&)-->
+        <para>This means that if L is constant, linearly interpolating N is exactly equivalent to
+            linearly interpolating the results of the lighting equation. And the addition of the
+            ambient term doesn't change this, since it is a constant and would not be affected by
+            linear interpolation.</para>
+        <para>When doing point lighting, you would have to interpolate both N and L. And that does
+            not yield the same results as linearly interpolating the two colors you get from the
+            lighting equation. This is a big part of the reason why the cylinder doesn't look
+            correct.</para>
+    </section>
+    <section>
+        <title>Fragment Lighting</title>
+        <para>So, in order to deal with interpolation artifacts, we need to interpolate the actual
+            light direction and normal, instead of just the results of the lighting equation. This
+            is called per-fragment lighting or just <glossterm>fragment lighting.</glossterm></para>
+        <para>There is a problem that needs to be dealt with first. Normals do not interpolate well.
+            Or rather, wildly different normals do not interpolate well. And light directions can be
+            very different.</para>
+        <para>Consider the large plane we have. The direction toward the light will be very
+            different at each vertex, so long as our light remains in relatively close proximity to
+            the plane.</para>
+        <para>Part of the problem is with interpolating values along the diagonal of our triangle.
+            Using two triangles to form a square plane does not mean that the values at the four
+            vertices interpolate the way you would expect. The plane is actually made of these two
+            triangles:</para>
+        <!--TODO: Show a picture of the two triangles composing the plane.-->
+        <para>The interpolation always happens between the three vertices of the particular
+            triangle. Which means that vertices near the diagonal will be basically doing a linear
+            interpolation between the two values on either end of that diagonal. This is not the
+            same thing as doing interpolation between all 4 values.</para>
+        <!--TODO: Show bilinear interpolation vs. triangular interpolation.-->
+        <para>In our case, this means that for points along the main diagonal, the light direction
+            will only be composed of the direction values from the two vertices on that diagonal.
+            This is not good. This wouldn't be much of a problem if the light direction did not
+            change much along the surface, but that is not the case here.</para>
+        <para>Since we cannot interpolate the light direction very well, we need to interpolate
+            something else. Something that does exhibit the characteristics we need.</para>
+        <para>Positions interpolate linearly quite well. So instead of interpolating the light
+            direction, we interpolate the components of the light direction. Namely, the two
+            positions. The light position is a constant, so we only need to interpolate the vertex
+            position.</para>
+        <para>Now, we could do this in any space. But for illustrative purposes, we will be doing
+            this in model space. That is, both the light position and vertex position will be in
+            model space.</para>
+        <para>One of the advantages of doing things in model space is that it gets rid of that pesky
+            matrix inverse/transpose we had to do to transform normals correctly. Indeed, normals
+            are not transformed at all. One of the disadvantages is that it requires computing an
+            inverse matrix for our light position, so that we can go from world space to model
+            space.</para>
+        <para>The <phrase role="propername">Fragment Point Lighting</phrase> tutorial shows off how
+            fragment lighting works.</para>
+    </section>
+    <section>
+        <title>Distance and Points</title>
+        <para/>
+    </section>
+    <section>
+        <?dbhtml filename="Tut09 In Review.html" ?>
+        <title>In Review</title>
+        <para/>
+        <section>
+            <title>Further Study</title>
+            <para>Try doing these things with the given programs.</para>
+            <itemizedlist>
+                <listitem>
+                    <para>When we used model space-based lighting computations, we had to perform an
+                        inverse on our matrix from the matrix stack to transform the light position
+                        from camera space to model space. However, it would be entirely possible to
+                        simply build an inverse matrix at the same time we build a regular matrix on
+                        our matrix stack. The inverse of a rotation matrix is just the rotation
+                        matrix with a negated angle; the inverse of a scale is just the
+                        multiplicative inverse of the scales, and the inverse of the translation is
+                        the negation of the translation vector.</para>
+                    <para>To do this, you will need to modify the <classname>MatrixStack</classname>
+                        class in a number of ways. It must store a second matrix representing the
+                        accumulated inverse matrix. When a transformation command is given to the
+                        stack, it must also generate the inverse matrix for this transform and
+                            <emphasis>left multiply</emphasis> this into the accumulated inverse.
+                        The push/pop will have to push/pop the inverse matrix as well. It can use
+                        the same stack, so long as the pop function puts the two matrices in the
+                        proper places.</para>
+                </listitem>
+            </itemizedlist>
+        </section>
+    </section>
+    <section>
+        <?dbhtml filename="Tut09 Glossary.html" ?>
+        <title>Glossary</title>
+        <glosslist>
+            <glossentry>
+                <glossterm>point light</glossterm>
+                <glossdef>
+                    <para/>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>fragment lighting</glossterm>
+                <glossdef>
+                    <para/>
+                </glossdef>
+            </glossentry>
+        </glosslist>
+    </section>
+    
+</chapter>

File Documents/Outline.xml

             <para>Concepts:</para>
             <itemizedlist>
                 <listitem>
-                    <para>Perspective-correct interpolation of vertex attributes.</para>
-                </listitem>
-                <listitem>
                     <para>Point lights.</para>
                 </listitem>
                 <listitem>
                     <para>Implementing per-fragment lighting.</para>
                 </listitem>
                 <listitem>
-                    <para>Tangent-space transform for per-fragment lighting.</para>
+                    <para>Talk about the artifact when lights get too close to the object. Talk
+                        about why it happens (surface being planar and not circular).</para>
+                </listitem>
+                <listitem>
+                    <para>Light attenuation.</para>
+                </listitem>
+                <listitem>
+                    <para>Distances in alternate spaces and how to compensate.</para>
+                </listitem>
+            </itemizedlist>
+        </section>
+        <section>
+            <title>Shininess</title>
+            <para>This tutorial introduces ways to make an object look shiny. Specifically specular
+                lighting and the Phong lighting model. There should be an animated light that shows
+                this off.</para>
+            <para>Concepts:</para>
+            <itemizedlist>
+                <listitem>
+                    <para>BDRFs: Lighting models that are a function of surface normal, angle to the
+                        light, and angle to the camera.</para>
+                </listitem>
+                <listitem>
+                    <para>The Phong specular lighting model. With both directional and point
+                        lights.</para>
                 </listitem>
             </itemizedlist>
         </section>
                 </listitem>
             </itemizedlist>
         </section>
-        <section>
-            <title>Shininess</title>
-            <para>This tutorial introduces ways to make an object look shiny. Specifically specular
-                lighting and the Phong lighting model. There should be an animated light or two that
-                shows this off.</para>
-            <para>Concepts:</para>
-            <itemizedlist>
-                <listitem>
-                    <para>BDRFs: Lighting models that are a function of surface normal, angle to the
-                        light, and angle to the camera.</para>
-                </listitem>
-                <listitem>
-                    <para>The Phong specular lighting model.</para>
-                </listitem>
-            </itemizedlist>
-        </section>
     </section>
     <section>
         <title>Texturing</title>
         <section>
-            <title>Texturing the World</title>
-            <para>This tutorial involves putting a texture on a simple, lit object.</para>
+            <title>Textures are not Pictures</title>
+            <para>This tutorial involves using a texture to define the specular value of an object
+                at a certain point.</para>
             <para>Concepts:</para>
             <itemizedlist>
                 <listitem>
+                    <para>Perspective-correct interpolation of vertex attributes.</para>
+                </listitem>
+                <listitem>
                     <para>Texture objects. An OpenGL object that holds images.</para>
                 </listitem>
                 <listitem>
                         units.</para>
                 </listitem>
                 <listitem>
-                    <para>Combining texture colors with the results of lighting.</para>
+                    <para>Using values from textures in lighting equations.</para>
                 </listitem>
             </itemizedlist>
         </section>
         <section>
             <title>More Images is Better</title>
-            <para>This tutorial shows a ground plane with a highly aliased texture. An animated
-                camera shows off the aliasing. Then we apply mipmapping and anisotropic filtering to
-                the surface to improve it.</para>
+            <para>This tutorial shows a ground plane with a highly aliased texture (as the diffuse
+                color). An animated camera shows off the aliasing. Then we apply mipmapping and
+                anisotropic filtering to the surface to improve it.</para>
             <para>Concepts:</para>
             <itemizedlist>
                 <listitem>

File Documents/Tutorial Documents.xpr

         </folder>
         <folder name="Illumination">
             <file name="Illumination/Tutorial%2008.xml"/>
+            <file name="Illumination/Tutorial%2009.xml"/>
         </folder>
         <folder name="Positioning">
             <file name="Positioning/Tutorial%2003.xml"/>

File Tut 09 Plane Lights/Fragment Directional Lighting.cpp

-#include <string>
-#include <vector>
-#include <stack>
-#include <math.h>
-#include <glloader/gl_3_2_comp.h>
-#include <GL/freeglut.h>
-#include "../framework/framework.h"
-#include "../framework/Mesh.h"
-#include "../framework/MatrixStack.h"
-#include "../framework/MousePole.h"
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
-
-struct ProgramData
-{
-	GLuint theProgram;
-
-	GLuint modelSpaceLightPosUnif;
-	GLuint lightIntensityUnif;
-	GLuint ambientIntensityUnif;
-
-	GLuint cameraToClipMatrixUnif;
-	GLuint modelToCameraMatrixUnif;
-	GLuint normalModelToCameraMatrixUnif;
-};
-
-struct UnlitProgData
-{
-	GLuint theProgram;
-
-	GLuint objectColorUnif;
-	GLuint cameraToClipMatrixUnif;
-	GLuint modelToCameraMatrixUnif;
-};
-
-float g_fzNear = 1.0f;
-float g_fzFar = 1000.0f;
-
-ProgramData g_WhiteAmbDiffuseColor;
-ProgramData g_VertexAmbDiffuseColor;
-ProgramData g_WhiteAmbFragDiffuseColor;
-ProgramData g_VertexAmbFragDiffuseColor;
-
-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.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
-	data.modelSpaceLightPosUnif = glGetUniformLocation(data.theProgram, "modelSpaceLightPos");
-	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
-	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
-
-	return data;
-}
-
-void InitializePrograms()
-{
-	g_WhiteAmbDiffuseColor = LoadLitProgram("ModelPosVertexLighting_PN.vert", "ColorPassthrough.frag");
-	g_VertexAmbDiffuseColor = LoadLitProgram("ModelPosVertexLighting_PCN.vert", "ColorPassthrough.frag");
-	g_WhiteAmbFragDiffuseColor = LoadLitProgram("FragmentLighting_PN.vert", "FragmentLighting.frag");
-	g_VertexAmbFragDiffuseColor = LoadLitProgram("FragmentLighting_PCN.vert", "FragmentLighting.frag");
-
-	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
-}
-
-Framework::Mesh *g_pCylinderMesh = NULL;
-Framework::Mesh *g_pPlaneMesh = NULL;
-Framework::Mesh *g_pCubeMesh = NULL;
-
-Framework::RadiusDef radiusDef = {5.0f, 3.0f, 200.0f, 1.5f, 0.5f};
-Framework::MousePole g_mousePole(glm::vec3(0.0f, 0.5f, 0.0f), radiusDef);
-
-namespace
-{
-	void MouseMotion(int x, int y)
-	{
-		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseButton(int button, int state, int x, int y)
-	{
-		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseWheel(int wheel, int direction, int x, int y)
-	{
-		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-}
-
-//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
-void init()
-{
-	InitializePrograms();
-
-	try
-	{
-		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
-		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
-		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
-	}
-	catch(std::exception &except)
-	{
-		printf(except.what());
-	}
-
- 	glutMouseFunc(MouseButton);
- 	glutMotionFunc(MouseMotion);
-	glutMouseWheelFunc(MouseWheel);
-
-	glEnable(GL_CULL_FACE);
-	glCullFace(GL_BACK);
-	glFrontFace(GL_CW);
-
-	glEnable(GL_DEPTH_TEST);
-	glDepthMask(GL_TRUE);
-	glDepthFunc(GL_LEQUAL);
-	glDepthRange(0.0f, 1.0f);
-	glEnable(GL_DEPTH_CLAMP);
-}
-
-static float g_fLightHeight = 1.5f;
-static float g_fLightRadius = 1.0f;
-
-glm::vec4 CalcLightPosition()
-{
-	const float fLoopDuration = 5.0f;
-	const float fScale = 3.14159f * 2.0f / fLoopDuration;
-
-	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
-
-	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
-
-	glm::vec4 ret(0.0f, g_fLightHeight, 0.0f, 1.0f);
-
-	ret.x = cosf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
-	ret.z = sinf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
-
-	return ret;
-}
-
-static float g_CylYaw = 0.0f;
-static float g_CylPitch = 0.0f;
-static float g_CylRoll = 0.0f;
-
-static bool g_bUseFragmentLighting = true;
-static bool g_bDrawColoredCyl = false;
-static bool g_bDrawLight = false;
-static bool g_bScaleCyl = false;
-
-//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)
-	{
-		Framework::MatrixStack modelMatrix;
-		modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
-
-		const glm::vec4 &worldLightPos = CalcLightPosition();
-
-		glm::vec4 lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
-
-		ProgramData *pWhiteProgram = NULL;
-		ProgramData *pVertColorProgram = NULL;
-
-		if(g_bUseFragmentLighting)
-		{
-			pWhiteProgram = &g_WhiteAmbFragDiffuseColor;
-			pVertColorProgram = &g_VertexAmbFragDiffuseColor;
-		}
-		else
-		{
-			pWhiteProgram = &g_WhiteAmbDiffuseColor;
-			pVertColorProgram = &g_VertexAmbDiffuseColor;
-		}
-
-		glUseProgram(pWhiteProgram->theProgram);
-		glUniform4f(pWhiteProgram->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(pWhiteProgram->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUseProgram(pVertColorProgram->theProgram);
-		glUniform4f(pVertColorProgram->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(pVertColorProgram->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUseProgram(0);
-
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-
-			//Render the ground plane.
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				glUseProgram(pWhiteProgram->theProgram);
-				glUniformMatrix4fv(pWhiteProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(modelMatrix.Top()));
-
-				glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
-				glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
-				glUniform3fv(pWhiteProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
-
-				glm::mat3 normMatrix(modelMatrix.Top());
-				glUniformMatrix3fv(pWhiteProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(normMatrix));
-				g_pPlaneMesh->Render();
-				glUseProgram(0);
-			}
-
-			//Render the Cylinder
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				modelMatrix.Translate(0.0f, 0.5f, 0.0f);
-
-				modelMatrix.RotateX(g_CylPitch);
-				modelMatrix.RotateY(g_CylYaw);
-				modelMatrix.RotateZ(g_CylRoll);
-
-				if(g_bScaleCyl)
-					modelMatrix.Scale(1.0f, 1.0f, 0.2f);
-
-				if(g_bDrawColoredCyl)
-				{
-					glUseProgram(pVertColorProgram->theProgram);
-					glUniformMatrix4fv(pVertColorProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(modelMatrix.Top()));
-
-					glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
-					glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
-					glUniform3fv(pVertColorProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
-
-					glm::mat3 normMatrix(modelMatrix.Top());
-					glUniformMatrix3fv(pVertColorProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(normMatrix));
-					g_pCylinderMesh->Render("tint");
-				}
-				else
-				{
-					glUseProgram(pWhiteProgram->theProgram);
-					glUniformMatrix4fv(pWhiteProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(modelMatrix.Top()));
-
-					glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
-					glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
-					glUniform3fv(pWhiteProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
-
-					glm::mat3 normMatrix(modelMatrix.Top());
-					glUniformMatrix3fv(pWhiteProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(normMatrix));
-					g_pCylinderMesh->Render("flat");
-				}
-				glUseProgram(0);
-			}
-
-			//Render the light
-			if(g_bDrawLight)
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				modelMatrix.Translate(glm::vec3(worldLightPos));
-				modelMatrix.Scale(0.1f, 0.1f, 0.1f);
-
-				glUseProgram(g_Unlit.theProgram);
-				glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(modelMatrix.Top()));
-				glUniform4f(g_Unlit.objectColorUnif, 0.8078f, 0.8706f, 0.9922f, 1.0f);
-				g_pCubeMesh->Render("flat");
-			}
-		}
-	}
-
-	glutPostRedisplay();
-	glutSwapBuffers();
-}
-
-//Called whenever the window is resized. The new window size is given, in pixels.
-//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
-void reshape (int w, int h)
-{
-	Framework::MatrixStack persMatrix;
-	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
-
-	glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_WhiteAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_VertexAmbDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_VertexAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_WhiteAmbFragDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_WhiteAmbFragDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_VertexAmbFragDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_VertexAmbFragDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_Unlit.theProgram);
-	glUniformMatrix4fv(g_Unlit.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(0);
-
-	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
-	glutPostRedisplay();
-}
-
-//Called whenever a key on the keyboard was pressed.
-//The key is given by the ''key'' parameter, which is in ASCII.
-//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
-//exit the program.
-void keyboard(unsigned char key, int x, int y)
-{
-	switch (key)
-	{
-	case 27:
-		delete g_pPlaneMesh;
-		delete g_pCylinderMesh;
-		delete g_pCubeMesh;
-		glutLeaveMainLoop();
-		break;
-	case 'w': g_CylPitch -= 11.25f; break;
-	case 's': g_CylPitch += 11.25f; break;
-	case 'd': g_CylRoll -= 11.25f; break;
-	case 'a': g_CylRoll += 11.25f; break;
-	case 'e': g_CylYaw -= 11.25f; break;
-	case 'q': g_CylYaw += 11.25f; break;
-	case 'W': g_CylPitch -= 4.0f; break;
-	case 'S': g_CylPitch += 4.0f; break;
-	case 'D': g_CylRoll -= 4.0f; break;
-	case 'A': g_CylRoll += 4.0f; break;
-	case 'E': g_CylYaw -= 4.0f; break;
-	case 'Q': g_CylYaw += 4.0f; break;
-		
-	case 32:
-		g_bDrawColoredCyl = !g_bDrawColoredCyl;
-		printf("Yaw: %f, Pitch: %f, Roll: %f\n", g_CylYaw, g_CylPitch, g_CylRoll);
-		break;
-
-	case 'i': g_fLightHeight += 0.2f; break;
-	case 'k': g_fLightHeight -= 0.2f; break;
-	case 'l': g_fLightRadius += 0.2f; break;
-	case 'j': g_fLightRadius -= 0.2f; break;
-
-	case 'I': g_fLightHeight += 0.05f; break;
-	case 'K': g_fLightHeight -= 0.05f; break;
-	case 'L': g_fLightRadius += 0.05f; break;
-	case 'J': g_fLightRadius -= 0.05f; break;
-
-	case 'y': g_bDrawLight = !g_bDrawLight; break;
-	case 't': g_bScaleCyl = !g_bScaleCyl; break;
-	}
-
-	if(g_fLightRadius < 0.2f)
-		g_fLightRadius = 0.2f;
-
-	glutPostRedisplay();
-}
-
-

File Tut 09 Plane Lights/Fragment Point Lighting.cpp

+#include <string>
+#include <vector>
+#include <stack>
+#include <math.h>
+#include <glloader/gl_3_2_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.h"
+#include "../framework/Mesh.h"
+#include "../framework/MatrixStack.h"
+#include "../framework/MousePole.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
+struct ProgramData
+{
+	GLuint theProgram;
+
+	GLuint modelSpaceLightPosUnif;
+	GLuint lightIntensityUnif;
+	GLuint ambientIntensityUnif;
+
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+	GLuint normalModelToCameraMatrixUnif;
+};
+
+struct UnlitProgData
+{
+	GLuint theProgram;
+
+	GLuint objectColorUnif;
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+ProgramData g_WhiteAmbDiffuseColor;
+ProgramData g_VertexAmbDiffuseColor;
+ProgramData g_WhiteAmbFragDiffuseColor;
+ProgramData g_VertexAmbFragDiffuseColor;
+
+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.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
+	data.modelSpaceLightPosUnif = glGetUniformLocation(data.theProgram, "modelSpaceLightPos");
+	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
+	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	g_WhiteAmbDiffuseColor = LoadLitProgram("ModelPosVertexLighting_PN.vert", "ColorPassthrough.frag");
+	g_VertexAmbDiffuseColor = LoadLitProgram("ModelPosVertexLighting_PCN.vert", "ColorPassthrough.frag");
+	g_WhiteAmbFragDiffuseColor = LoadLitProgram("FragmentLighting_PN.vert", "FragmentLighting.frag");
+	g_VertexAmbFragDiffuseColor = LoadLitProgram("FragmentLighting_PCN.vert", "FragmentLighting.frag");
+
+	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
+}
+
+Framework::Mesh *g_pCylinderMesh = NULL;
+Framework::Mesh *g_pPlaneMesh = NULL;
+Framework::Mesh *g_pCubeMesh = NULL;
+
+Framework::RadiusDef radiusDef = {5.0f, 3.0f, 200.0f, 1.5f, 0.5f};
+Framework::MousePole g_mousePole(glm::vec3(0.0f, 0.5f, 0.0f), radiusDef);
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseButton(int button, int state, int x, int y)
+	{
+		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseWheel(int wheel, int direction, int x, int y)
+	{
+		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+}
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializePrograms();
+
+	try
+	{
+		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
+		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
+		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+ 	glutMouseFunc(MouseButton);
+ 	glutMotionFunc(MouseMotion);
+	glutMouseWheelFunc(MouseWheel);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(GL_TRUE);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(0.0f, 1.0f);
+	glEnable(GL_DEPTH_CLAMP);
+}
+
+static float g_fLightHeight = 1.5f;
+static float g_fLightRadius = 1.0f;
+
+glm::vec4 CalcLightPosition()
+{
+	const float fLoopDuration = 5.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
+
+	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
+
+	glm::vec4 ret(0.0f, g_fLightHeight, 0.0f, 1.0f);
+
+	ret.x = cosf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
+	ret.z = sinf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
+
+	return ret;
+}
+
+static float g_CylYaw = 0.0f;
+static float g_CylPitch = 0.0f;
+static float g_CylRoll = 0.0f;
+
+static bool g_bUseFragmentLighting = true;
+static bool g_bDrawColoredCyl = false;
+static bool g_bDrawLight = false;
+static bool g_bScaleCyl = false;
+
+//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)
+	{
+		Framework::MatrixStack modelMatrix;
+		modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
+
+		const glm::vec4 &worldLightPos = CalcLightPosition();
+
+		glm::vec4 lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
+
+		ProgramData *pWhiteProgram = NULL;
+		ProgramData *pVertColorProgram = NULL;
+
+		if(g_bUseFragmentLighting)
+		{
+			pWhiteProgram = &g_WhiteAmbFragDiffuseColor;
+			pVertColorProgram = &g_VertexAmbFragDiffuseColor;
+		}
+		else
+		{
+			pWhiteProgram = &g_WhiteAmbDiffuseColor;
+			pVertColorProgram = &g_VertexAmbDiffuseColor;
+		}
+
+		glUseProgram(pWhiteProgram->theProgram);
+		glUniform4f(pWhiteProgram->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
+		glUniform4f(pWhiteProgram->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
+		glUseProgram(pVertColorProgram->theProgram);
+		glUniform4f(pVertColorProgram->lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
+		glUniform4f(pVertColorProgram->ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
+		glUseProgram(0);
+
+		{
+			Framework::MatrixStackPusher push(modelMatrix);
+
+			//Render the ground plane.
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				glUseProgram(pWhiteProgram->theProgram);
+				glUniformMatrix4fv(pWhiteProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+
+				glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
+				glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
+				glUniform3fv(pWhiteProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
+
+				glm::mat3 normMatrix(modelMatrix.Top());
+				glUniformMatrix3fv(pWhiteProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(normMatrix));
+				g_pPlaneMesh->Render();
+				glUseProgram(0);
+			}
+
+			//Render the Cylinder
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				modelMatrix.Translate(0.0f, 0.5f, 0.0f);
+
+				modelMatrix.RotateX(g_CylPitch);
+				modelMatrix.RotateY(g_CylYaw);
+				modelMatrix.RotateZ(g_CylRoll);
+
+				if(g_bScaleCyl)
+					modelMatrix.Scale(1.0f, 1.0f, 0.2f);
+
+				if(g_bDrawColoredCyl)
+				{
+					glUseProgram(pVertColorProgram->theProgram);
+					glUniformMatrix4fv(pVertColorProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
+						glm::value_ptr(modelMatrix.Top()));
+
+					glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
+					glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
+					glUniform3fv(pVertColorProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
+
+					glm::mat3 normMatrix(modelMatrix.Top());
+					glUniformMatrix3fv(pVertColorProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
+						glm::value_ptr(normMatrix));
+					g_pCylinderMesh->Render("tint");
+				}
+				else
+				{
+					glUseProgram(pWhiteProgram->theProgram);
+					glUniformMatrix4fv(pWhiteProgram->modelToCameraMatrixUnif, 1, GL_FALSE,
+						glm::value_ptr(modelMatrix.Top()));
+
+					glm::mat4 invTransform = glm::inverse(modelMatrix.Top());
+					glm::vec4 lightPosModelSpace = invTransform * lightPosCameraSpace;
+					glUniform3fv(pWhiteProgram->modelSpaceLightPosUnif, 1, glm::value_ptr(lightPosModelSpace));
+
+					glm::mat3 normMatrix(modelMatrix.Top());
+					glUniformMatrix3fv(pWhiteProgram->normalModelToCameraMatrixUnif, 1, GL_FALSE,
+						glm::value_ptr(normMatrix));
+					g_pCylinderMesh->Render("flat");
+				}
+				glUseProgram(0);
+			}
+
+			//Render the light
+			if(g_bDrawLight)
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				modelMatrix.Translate(glm::vec3(worldLightPos));
+				modelMatrix.Scale(0.1f, 0.1f, 0.1f);
+
+				glUseProgram(g_Unlit.theProgram);
+				glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+				glUniform4f(g_Unlit.objectColorUnif, 0.8078f, 0.8706f, 0.9922f, 1.0f);
+				g_pCubeMesh->Render("flat");
+			}
+		}
+	}
+
+	glutPostRedisplay();
+	glutSwapBuffers();
+}
+
+//Called whenever the window is resized. The new window size is given, in pixels.
+//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
+void reshape (int w, int h)
+{
+	Framework::MatrixStack persMatrix;
+	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
+
+	glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_WhiteAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_VertexAmbDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_VertexAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_WhiteAmbFragDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_WhiteAmbFragDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_VertexAmbFragDiffuseColor.theProgram);
+	glUniformMatrix4fv(g_VertexAmbFragDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(g_Unlit.theProgram);
+	glUniformMatrix4fv(g_Unlit.cameraToClipMatrixUnif, 1, GL_FALSE,
+		glm::value_ptr(persMatrix.Top()));
+	glUseProgram(0);
+
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+	glutPostRedisplay();
+}
+
+//Called whenever a key on the keyboard was pressed.
+//The key is given by the ''key'' parameter, which is in ASCII.
+//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
+//exit the program.
+void keyboard(unsigned char key, int x, int y)
+{
+	switch (key)
+	{
+	case 27:
+		delete g_pPlaneMesh;
+		delete g_pCylinderMesh;
+		delete g_pCubeMesh;
+		glutLeaveMainLoop();
+		break;
+	case 'w': g_CylPitch -= 11.25f; break;
+	case 's': g_CylPitch += 11.25f; break;
+	case 'd': g_CylRoll -= 11.25f; break;
+	case 'a': g_CylRoll += 11.25f; break;
+	case 'e': g_CylYaw -= 11.25f; break;
+	case 'q': g_CylYaw += 11.25f; break;
+	case 'W': g_CylPitch -= 4.0f; break;
+	case 'S': g_CylPitch += 4.0f; break;
+	case 'D': g_CylRoll -= 4.0f; break;
+	case 'A': g_CylRoll += 4.0f; break;
+	case 'E': g_CylYaw -= 4.0f; break;
+	case 'Q': g_CylYaw += 4.0f; break;
+		
+	case 32:
+		g_bDrawColoredCyl = !g_bDrawColoredCyl;
+		printf("Yaw: %f, Pitch: %f, Roll: %f\n", g_CylYaw, g_CylPitch, g_CylRoll);
+		break;
+
+	case 'i': g_fLightHeight += 0.2f; break;
+	case 'k': g_fLightHeight -= 0.2f; break;
+	case 'l': g_fLightRadius += 0.2f; break;
+	case 'j': g_fLightRadius -= 0.2f; break;
+
+	case 'I': g_fLightHeight += 0.05f; break;
+	case 'K': g_fLightHeight -= 0.05f; break;
+	case 'L': g_fLightRadius += 0.05f; break;
+	case 'J': g_fLightRadius -= 0.05f; break;
+
+	case 'y': g_bDrawLight = !g_bDrawLight; break;
+	case 't': g_bScaleCyl = !g_bScaleCyl; break;
+	}
+
+	if(g_fLightRadius < 0.2f)
+		g_fLightRadius = 0.2f;
+
+	glutPostRedisplay();
+}
+
+

File Tut 09 Plane Lights/Perspective Interpolation.cpp

-#include <string>
-#include <vector>
-#include <stack>
-#include <math.h>
-#include <glloader/gl_3_2_comp.h>
-#include <GL/freeglut.h>
-#include "../framework/framework.h"
-#include "../framework/Mesh.h"
-#include "../framework/MatrixStack.h"
-#include "../framework/MousePole.h"
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
-
-struct ProgramData
-{
-	GLuint theProgram;
-
-	GLuint cameraToClipMatrixUnif;
-};
-
-float g_fzNear = 1.0f;
-float g_fzFar = 1000.0f;
-
-ProgramData g_SmoothInterp;
-ProgramData g_LinearInterp;
-
-ProgramData LoadProgram(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.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
-
-	return data;
-}
-
-void InitializePrograms()
-{
-	g_SmoothInterp = LoadProgram("SmoothVertexColors.vert", "SmoothVertexColors.frag");
-	g_LinearInterp = LoadProgram("NoCorrectVertexColors.vert", "NoCorrectVertexColors.frag");
-
-	Framework::MatrixStack persMatrix;
-	persMatrix.Perspective(60.0f, 1.0f, g_fzNear, g_fzFar);
-
-	glUseProgram(g_SmoothInterp.theProgram);
-	glUniformMatrix4fv(g_SmoothInterp.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_LinearInterp.theProgram);
-	glUniformMatrix4fv(g_LinearInterp.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(0);
-}
-
-Framework::Mesh *g_pRealHallway = NULL;
-Framework::Mesh *g_pFauxHallway = NULL;
-
-//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
-void init()
-{
-	InitializePrograms();
-
-	try
-	{
-		g_pRealHallway = new Framework::Mesh("RealHallway.xml");
-		g_pFauxHallway = new Framework::Mesh("FauxHallway.xml");
-	}
-	catch(std::exception &except)
-	{
-		printf(except.what());
-	}
-}
-
-static bool g_bUseFakeHallway = false;
-static bool g_bUseSmoothInterpolation = 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.
-
-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_pRealHallway && g_pFauxHallway)
-	{
-		if(g_bUseSmoothInterpolation)
-			glUseProgram(g_SmoothInterp.theProgram);
-		else
-			glUseProgram(g_LinearInterp.theProgram);
-
-		if(g_bUseFakeHallway)
-			g_pFauxHallway->Render();
-		else
-			g_pRealHallway->Render();
-
-		glUseProgram(0);
-	}
-
-	glutSwapBuffers();
-}
-
-//Called whenever the window is resized. The new window size is given, in pixels.
-//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
-void reshape (int w, int h)
-{
-	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
-	glutPostRedisplay();
-}
-
-//Called whenever a key on the keyboard was pressed.
-//The key is given by the ''key'' parameter, which is in ASCII.
-//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
-//exit the program.
-void keyboard(unsigned char key, int x, int y)
-{
-	switch (key)
-	{
-	case 27:
-		delete g_pRealHallway;
-		delete g_pFauxHallway;
-		glutLeaveMainLoop();
-		break;
-
-	case 's':
-		g_bUseFakeHallway = !g_bUseFakeHallway;
-		if(g_bUseFakeHallway)
-			printf("Fake Hallway.\n");
-		else
-			printf("Real Hallway.\n");
-		break;
-
-	case 'w':
-		g_bUseSmoothInterpolation = !g_bUseSmoothInterpolation;
-		if(g_bUseSmoothInterpolation)
-			printf("Perspective correct interpolation.\n");
-		else
-			printf("Just linear interpolation.\n");
-		break;
-
-	case 32:
-		//Reload.
-		delete g_pRealHallway;
-		delete g_pFauxHallway;
-		g_pRealHallway = new Framework::Mesh("RealHallway.xml");
-		g_pFauxHallway = new Framework::Mesh("FauxHallway.xml");
-		break;
-	}
-
-	glutPostRedisplay();
-}
-
-

File Tut 09 Plane Lights/Vertex Directional Lighting.cpp

-#include <string>
-#include <vector>
-#include <stack>
-#include <math.h>
-#include <glloader/gl_3_2_comp.h>
-#include <GL/freeglut.h>
-#include "../framework/framework.h"
-#include "../framework/Mesh.h"
-#include "../framework/MatrixStack.h"
-#include "../framework/MousePole.h"
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
-
-struct ProgramData
-{
-	GLuint theProgram;
-
-	GLuint lightPosUnif;
-	GLuint lightIntensityUnif;
-	GLuint ambientIntensityUnif;
-
-	GLuint cameraToClipMatrixUnif;
-	GLuint modelToCameraMatrixUnif;
-	GLuint normalModelToCameraMatrixUnif;
-};
-
-struct UnlitProgData
-{
-	GLuint theProgram;
-
-	GLuint objectColorUnif;
-	GLuint cameraToClipMatrixUnif;
-	GLuint modelToCameraMatrixUnif;
-};
-
-float g_fzNear = 1.0f;
-float g_fzFar = 1000.0f;
-
-ProgramData g_WhiteAmbDiffuseColor;
-ProgramData g_VertexAmbDiffuseColor;
-
-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.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
-	data.lightPosUnif = glGetUniformLocation(data.theProgram, "lightPos");
-	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
-	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
-
-	return data;
-}
-
-void InitializePrograms()
-{
-	g_WhiteAmbDiffuseColor = LoadLitProgram("PosVertexLighting_PN.vert", "ColorPassthrough.frag");
-	g_VertexAmbDiffuseColor = LoadLitProgram("PosVertexLighting_PCN.vert", "ColorPassthrough.frag");
-	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
-}
-
-Framework::Mesh *g_pCylinderMesh = NULL;
-Framework::Mesh *g_pPlaneMesh = NULL;
-Framework::Mesh *g_pCubeMesh = NULL;
-
-Framework::RadiusDef radiusDef = {5.0f, 3.0f, 20.0f, 1.5f, 0.5f};
-Framework::MousePole g_mousePole(glm::vec3(0.0f, 0.5f, 0.0f), radiusDef);
-
-namespace
-{
-	void MouseMotion(int x, int y)
-	{
-		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseButton(int button, int state, int x, int y)
-	{
-		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseWheel(int wheel, int direction, int x, int y)
-	{
-		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-}
-
-//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
-void init()
-{
-	InitializePrograms();
-
-	try
-	{
-		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
-		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
-		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
-	}
-	catch(std::exception &except)
-	{
-		printf(except.what());
-	}
-
- 	glutMouseFunc(MouseButton);
- 	glutMotionFunc(MouseMotion);
-	glutMouseWheelFunc(MouseWheel);
-
-	glEnable(GL_CULL_FACE);
-	glCullFace(GL_BACK);
-	glFrontFace(GL_CW);
-
-	glEnable(GL_DEPTH_TEST);
-	glDepthMask(GL_TRUE);
-	glDepthFunc(GL_LEQUAL);
-	glDepthRange(0.0f, 1.0f);
-	glEnable(GL_DEPTH_CLAMP);
-}
-
-static float g_fLightHeight = 1.5f;
-static float g_fLightRadius = 1.0f;
-
-glm::vec4 CalcLightPosition()
-{
-	const float fLoopDuration = 5.0f;
-	const float fScale = 3.14159f * 2.0f / fLoopDuration;
-
-	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
-
-	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
-
-	glm::vec4 ret(0.0f, g_fLightHeight, 0.0f, 1.0f);
-
-	ret.x = cosf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
-	ret.z = sinf(fCurrTimeThroughLoop * fScale) * g_fLightRadius;
-
-	return ret;
-}
-
-static float g_CylYaw = 0.0f;
-static float g_CylPitch = 0.0f;
-static float g_CylRoll = 0.0f;
-
-static bool g_bDrawColoredCyl = false;
-static bool g_bDrawLight = false;
-
-//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)
-	{
-		Framework::MatrixStack modelMatrix;
-		modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
-
-		const glm::vec4 &worldLightPos = CalcLightPosition();
-
-		glm::vec4 lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
-
-		glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-		glUniform4f(g_WhiteAmbDiffuseColor.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(g_WhiteAmbDiffuseColor.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUseProgram(g_VertexAmbDiffuseColor.theProgram);
-		glUniform4f(g_VertexAmbDiffuseColor.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(g_VertexAmbDiffuseColor.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-
-		glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-		glUniform3fv(g_WhiteAmbDiffuseColor.lightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
-		glUseProgram(g_VertexAmbDiffuseColor.theProgram);
-		glUniform3fv(g_VertexAmbDiffuseColor.lightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
-		glUseProgram(0);
-
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-
-			//Render the ground plane.
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-				glUniformMatrix4fv(g_WhiteAmbDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(modelMatrix.Top()));
-				glm::mat3 normMatrix(modelMatrix.Top());
-				glUniformMatrix3fv(g_WhiteAmbDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(normMatrix));
-				g_pPlaneMesh->Render();
-				glUseProgram(0);
-			}
-
-			//Render the Cylinder
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				modelMatrix.Translate(0.0f, 0.5f, 0.0f);
-
-				modelMatrix.RotateX(g_CylPitch);
-				modelMatrix.RotateY(g_CylYaw);
-				modelMatrix.RotateZ(g_CylRoll);
-
-				if(g_bDrawColoredCyl)
-				{
-					glUseProgram(g_VertexAmbDiffuseColor.theProgram);
-					glUniformMatrix4fv(g_VertexAmbDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(modelMatrix.Top()));
-					glm::mat3 normMatrix(modelMatrix.Top());
-					glUniformMatrix3fv(g_VertexAmbDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(normMatrix));
-					g_pCylinderMesh->Render("tint");
-				}
-				else
-				{
-					glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-					glUniformMatrix4fv(g_WhiteAmbDiffuseColor.modelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(modelMatrix.Top()));
-					glm::mat3 normMatrix(modelMatrix.Top());
-					glUniformMatrix3fv(g_WhiteAmbDiffuseColor.normalModelToCameraMatrixUnif, 1, GL_FALSE,
-						glm::value_ptr(normMatrix));
-					g_pCylinderMesh->Render("flat");
-				}
-				glUseProgram(0);
-			}
-
-			//Render the light
-			if(g_bDrawLight)
-			{
-				Framework::MatrixStackPusher push(modelMatrix);
-
-				modelMatrix.Translate(glm::vec3(worldLightPos));
-				modelMatrix.Scale(0.1f, 0.1f, 0.1f);
-
-				glUseProgram(g_Unlit.theProgram);
-				glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
-					glm::value_ptr(modelMatrix.Top()));
-				glUniform4f(g_Unlit.objectColorUnif, 0.8078f, 0.8706f, 0.9922f, 1.0f);
-				g_pCubeMesh->Render("flat");
-			}
-		}
-	}
-
-	glutPostRedisplay();
-	glutSwapBuffers();
-}
-
-//Called whenever the window is resized. The new window size is given, in pixels.
-//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
-void reshape (int w, int h)
-{
-	Framework::MatrixStack persMatrix;
-	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
-
-	glUseProgram(g_WhiteAmbDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_WhiteAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_VertexAmbDiffuseColor.theProgram);
-	glUniformMatrix4fv(g_VertexAmbDiffuseColor.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(g_Unlit.theProgram);
-	glUniformMatrix4fv(g_Unlit.cameraToClipMatrixUnif, 1, GL_FALSE,
-		glm::value_ptr(persMatrix.Top()));
-	glUseProgram(0);
-
-	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
-	glutPostRedisplay();
-}
-
-//Called whenever a key on the keyboard was pressed.
-//The key is given by the ''key'' parameter, which is in ASCII.
-//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
-//exit the program.
-void keyboard(unsigned char key, int x, int y)
-{
-	switch (key)
-	{
-	case 27:
-		delete g_pPlaneMesh;
-		delete g_pCylinderMesh;
-		delete g_pCubeMesh;
-		glutLeaveMainLoop();
-		break;
-	case 'w': g_CylPitch -= 11.25f; break;
-	case 's': g_CylPitch += 11.25f; break;
-	case 'd': g_CylRoll -= 11.25f; break;
-	case 'a': g_CylRoll += 11.25f; break;
-	case 'e': g_CylYaw -= 11.25f; break;
-	case 'q': g_CylYaw += 11.25f; break;
-	case 'W': g_CylPitch -= 4.0f; break;
-	case 'S': g_CylPitch += 4.0f; break;
-	case 'D': g_CylRoll -= 4.0f; break;
-	case 'A': g_CylRoll += 4.0f; break;
-	case 'E': g_CylYaw -= 4.0f; break;
-	case 'Q': g_CylYaw += 4.0f; break;
-		
-	case 32:
-		g_bDrawColoredCyl = !g_bDrawColoredCyl;
-		printf("Yaw: %f, Pitch: %f, Roll: %f\n", g_CylYaw, g_CylPitch, g_CylRoll);
-		break;
-
-	case 'i': g_fLightHeight += 0.2f; break;
-	case 'k': g_fLightHeight -= 0.2f; break;
-	case 'l': g_fLightRadius += 0.2f; break;
-	case 'j': g_fLightRadius -= 0.2f; break;
-
-	case 'I': g_fLightHeight += 0.05f; break;
-	case 'K': g_fLightHeight -= 0.05f; break;
-	case 'L': g_fLightRadius += 0.05f; break;
-	case 'J': g_fLightRadius -= 0.05f; break;
-
-	case 'y': g_bDrawLight = !g_bDrawLight; break;
-	}
-
-	if(g_fLightRadius < 0.2f)
-		g_fLightRadius = 0.2f;
-
-	glutPostRedisplay();
-}
-
-

File Tut 09 Plane Lights/Vertex Point Lighting.cpp

+#include <string>
+#include <vector>
+#include <stack>
+#include <math.h>
+#include <glloader/gl_3_2_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.h"
+#include "../framework/Mesh.h"
+#include "../framework/MatrixStack.h"
+#include "../framework/MousePole.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
+struct ProgramData
+{
+	GLuint theProgram;
+
+	GLuint lightPosUnif;
+	GLuint lightIntensityUnif;
+	GLuint ambientIntensityUnif;
+
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+	GLuint normalModelToCameraMatrixUnif;
+};
+
+struct UnlitProgData
+{
+	GLuint theProgram;
+
+	GLuint objectColorUnif;
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+ProgramData g_WhiteAmbDiffuseColor;
+ProgramData g_VertexAmbDiffuseColor;
+
+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.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
+	data.lightPosUnif = glGetUniformLocation(data.theProgram, "lightPos");
+	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
+	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	g_WhiteAmbDiffuseColor = LoadLitProgram("PosVertexLighting_PN.vert", "ColorPassthrough.frag");
+	g_VertexAmbDiffuseColor = LoadLitProgram("PosVertexLighting_PCN.vert", "ColorPassthrough.frag");
+	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
+}
+
+Framework::Mesh *g_pCylinderMesh = NULL;
+Framework::Mesh *g_pPlaneMesh = NULL;
+Framework::Mesh *g_pCubeMesh = NULL;
+
+Framework::RadiusDef radiusDef = {5.0f, 3.0f, 20.0f, 1.5f, 0.5f};
+Framework::MousePole g_mousePole(glm::vec3(0.0f, 0.5f, 0.0f), radiusDef);
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseButton(int button, int state, int x, int y)
+	{
+		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseWheel(int wheel, int direction, int x, int y)
+	{
+		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+}
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializePrograms();
+
+	try
+	{
+		g_pCylinderMesh = new Framework::Mesh("UnitCylinder.xml");
+		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
+		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+ 	glutMouseFunc(MouseButton);
+ 	glutMotionFunc(MouseMotion);
+	glutMouseWheelFunc(MouseWheel);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(GL_TRUE);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(0.0f, 1.0f);
+	glEnable(GL_DEPTH_CLAMP);
+}
+
+static float g_fLightHeight = 1.5f;
+static float g_fLightRadius = 1.0f;
+
+glm::vec4 CalcLightPosition()