Jason McKesson avatar Jason McKesson committed a6c11fc

Start on Tutorial 6.

Comments (0)

Files changed (16)

Documents/Basics/Tutorial 01.xml

                         <varname>positionBufferObject</varname>. This piece of vertex data contains
                     32-bit float values, and each piece is a sequence of 4 of them. The data starts
                     at the 0th byte of the buffer object, and each set of 4 32-bit floats is tightly
-                    packed together.</quote> This means that our data of 24 floats represents enough
+                    packed together.</quote> This means that our data of 12 floats represents enough
                 information for the 3 vertices of a single triangle; this is exactly what we
                 want.</para>
             <para>The specifics of this function call will be discussed in later tutorials.</para>

Documents/Outline.xml

                 </listitem>
                 <listitem>
                     <para>Object-to-camera transform. How to compute the transformation from
-                        object-space to camera-space.</para>
+                        object-space to camera-space. Handle scale, rotation, and
+                        translation.</para>
+                </listitem>
+                <listitem>
+                    <para>Composing multiple object-to-camera transformations. Deal with the
+                        differences with regard to the order of transformations.</para>
+                </listitem>
+                <listitem>
+                    <para>Handle object hierarchies with a matrix stack.</para>
                 </listitem>
                 <listitem>
                     <para>Uniform Buffer Objects. Use multiple different programs, so have UBOs for
             <para>Tutorial sub-files:</para>
             <orderedlist>
                 <listitem>
-                    <para>Replicate the same object with different translations and scales. Both
-                        uniform and non-uniform. Animate them.</para>
+                    <para>Replicate the same object with scales, both uniform and non-uniform. Also
+                        have translations. Animate them.</para>
                 </listitem>
                 <listitem>
                     <para>Replicate the same object with different orientations and translations.
                         Animate them.</para>
                 </listitem>
                 <listitem>
+                    <para>Transformation composition, via matrix multiplication.</para>
+                </listitem>
+                <listitem>
+                    <para>Have objects composed of hierarchies of transformations. Animate these
+                        transformations in motion.</para>
+                </listitem>
+                <listitem>
                     <para>Have multiple different object geometries, with their own individual
                         transforms. Animate the transforms. Objects have different programs attached
                         that have different fragment shaders (and possibly vertex shaders). Use
                         space.</para>
                 </listitem>
                 <listitem>
+                    <para>Transform composition. Taking multiple transformation matrices and
+                        converting them into one matrix.</para>
+                </listitem>
+                <listitem>
                     <para>The dangers of having an explicit world space (precision problems with
                         large numbers).</para>
                 </listitem>
                         lights. Combining results from both kinds of lighting into a single
                         value.</para>
                 </listitem>
+                <listitem>
+                    <para>Perspective-correct interpolation of vertex attributes.</para>
+                </listitem>
             </itemizedlist>
         </section>
         <section>
                         you sample a texture.</para>
                 </listitem>
                 <listitem>
+                    <para>Sampler objects.</para>
+                </listitem>
+                <listitem>
                     <para>The GLSL side of texturing. Samplers and texture functions in fragment
                         shaders.</para>
                 </listitem>
                     <para>Using textures for non-color information. Also, scaling of the data that
                         comes out of the image.</para>
                 </listitem>
-            </itemizedlist>
-        </section>
-        <section>
-            <title>The Bumpy Mountain</title>
-            <para>Build a height field, but with more fine details. This requires multiple textures:
-                a height texture and a more detailed bump map on top of it. Fill in the details with
-                a bump map. Obviously, this will need to have a light in the scene.</para>
-            <para>Concepts:</para>
-            <itemizedlist>
                 <listitem>
                     <para>Constructing normals from the height field in the vertex shader.</para>
                 </listitem>
                         it in OpenGL.</para>
                 </listitem>
                 <listitem>
-                    <para>Backface culling. Making sure that the back faces of blended objects don't
-                        get rendered.</para>
-                </listitem>
-                <listitem>
                     <para>How blending interacts with depth writing and testing. Namely, that you
                         have to manually sort objects now: turn depth writes off and depth tests
                         on.</para>
                     <para>The Phong specular lighting model.</para>
                 </listitem>
                 <listitem>
-                    <para>Using a texture's value to control the strength of the Phong curve.
-                        Introduce floating-point textures here.</para>
+                    <para>Using a texture's value to control the strength of the Phong curve and
+                        other lighting parameters. Introduce floating-point textures here.</para>
                 </listitem>
             </itemizedlist>
         </section>
         <title>Functionality that needs tutorials</title>
         <glosslist>
             <glossentry>
-                <glossterm>Hierarchical spaces.</glossterm>
+                <glossterm>Debugging</glossterm>
                 <glossdef>
-                    <para>Matrix stacks and such.</para>
-                    <para>Might be shown off with a robot or something that moves.</para>
+                    <para>How to debug problems in OpenGL.</para>
                 </glossdef>
             </glossentry>
             <glossentry>

Documents/Positioning/Tutorial 04.xml

                     </imageobject>
                 </mediaobject>
                 <caption>
-                    <para>The projection of the point P onto the projection plane, located at the
-                        origin. R is the projection and E is the eye point.</para>
+                    <para>The projection of the point P onto the projection plane. This plane is at
+                        an offset of E<subscript>z</subscript> compared to the eye point, which is
+                        fixed at the origin. R is the projected point.</para>
                 </caption>
             </figure>
-            <para>What we have are two similar right triangles; the triangle formed by E, R and the
-                origin; and the triangle formed by E, P, and P<subscript>z</subscript>. We have the
-                eye position and the position of the unprojected point. To find the location of R,
-                we simply do this:</para>
+            <para>What we have are two similar right triangles; the triangle formed by E, R and
+                    E<subscript>z</subscript>the origin; and the triangle formed by E, P, and
+                    P<subscript>z</subscript>+E<subscript>z</subscript>. We have the eye position
+                and the position of the unprojected point. To find the location of R, we simply do
+                this:</para>
             <equation>
                 <title>Perspective Computation</title>
                 <mediaobject>

Documents/Positioning/Tutorial 05.xml

                 half-space. If the camera range goes from [-500, -1000], then half of NDC space
                 represents the range from [-500, -666.67]. This is 33.3% of the camera space range
                 mapping to 50% of the NDC range. However, if the camera range goes from [-1, -1000],
-                fully <emphasis>half</emphasis> of NDC space will represent only [-1, -1.998]; less
-                than 0.1% of the range.</para>
+                fully <emphasis>half</emphasis> of NDC space will represent only [-1, -1.998] in
+                camera space; less than 0.1% of the range.</para>
             <para>This has real consequences for the precision of your depth buffer. Earlier, we
                 said that the depth buffer stores floating-point values. While this is conceptually
                 true, most depth buffers actually use fixed-point values and convert them into
                     equally small.</para>
                 <para>First, it needs to be pointed out that a 24-bit depth buffer only goes from 0
                     to 16,777,215. Even if the depth values were evenly distributed, you would only
-                    get a resolution of 4th of an inch.</para>
+                    get a resolution of 1/4th of an inch.</para>
                 <para>Second, this range is starting to come perilously close to the issues with
                         <emphasis>floating-point</emphasis> precision. Yes, this still provides a
                     lot of precision, but remember: the depth range is for the current view. This
                     means that your world is probably much larger than this. If you're getting
-                    numbers that large, you should be starting to worry about floating-point
+                    numbers that large, you may need to start worrying about floating-point
                     precision error in computing these positions. There are certainly ways around it
                     (and we will discuss some later), but if you need a camera-space range that
                     large, you may run into other problems at the same time.</para>
                     up-close. If you think z-fighting looks bad when it happens with a distant
                     object, imagine how bad it will look if it's up in your face. Even if you could
                     make the z-values linear, it could cause problems in near objects.</para>
-                <para>Fifth, if you really, <emphasis>really</emphasis> need a camera range this
-                    large, you can play some tricks with the depth range.</para>
+                <para>Fifth, if you really need a camera range this large, you can play some tricks
+                    with the depth range. But only do this if you actually do get z-fighting; don't
+                    simply do it because you have a large camera range.</para>
                 <para>The camera range defines how the perspective matrix transforms the Z to
                     clip-space and therefore NDC space. The <emphasis>depth</emphasis> range defines
                     what part of the [0, 1] range of window coordinates that the NDC depth maps to.
         <para>And while this can <quote>function</quote> as a solution, it isn't exactly good. It
             limits what you can do with objects and so forth.</para>
         <para>A more reasonable mechanism is <glossterm>depth clamping</glossterm>. What this does
-            is turn off near/far plane clipping altogether. Instead, simply causes the depth for
-            these fragments to be the minimum or maximum values, depending on which plane they clip
-            against.</para>
+            is turn off camera near/far plane clipping altogether. Instead, the depth for these
+            fragments are clamped to the [-1, 1] range in NDC space.</para>
         <para>We can see this in the <phrase role="propername">Depth Clamping</phrase> tutorial.
             This tutorial is identical to the vertex clipping one, except that the
                 <function>keyboard</function> function has changed as follows:</para>
             near the planes. Similar problems happen with the far plane, though backface culling can
             be a help in some cases.</para>
         <note>
-            <para>We defined depth clamping as, in part, turning off clipping. If you're wondering
-                what happens when you have depth clamping, which turns off clipping, and a
-                clip-space W &lt;= 0, then... well, OpenGL doesn't say. At least, it doesn't say
-                specifically. All it says is that clipping against the near and far planes stops and
-                that fragment depth values generated outside of the expected depth range are clamped
-                to that range. No, really, that's <emphasis>all</emphasis> it says.</para>
+            <para>We defined depth clamping as, in part, turning off clipping against the camera
+                near and far planes. If you're wondering what happens when you have depth clamping,
+                which turns off clipping, and a clip-space W &lt;= 0, it's simple. In camera space,
+                near and far clipping is represented as turning a pyramid into a frustum: cutting
+                off the top and bottom. If near/far clipping isn't active, then the frustum becomes
+                a pyramid. The other 4 clipping planes are still fully in effect. Clip-space
+                vertices with a W of less than 0 are all outside of the boundary of any of the other
+                four clipping planes. And the only clip-space point with a W of 0 that is within
+                this volume is the homogeneous origin point: (0, 0, 0, 0); everything else will be
+                clipped.</para>
         </note>
     </section>
     <section>
         <para>In this tutorial, you have learned about the following:</para>
         <itemizedlist>
             <listitem>
-                <para>Vertex array objects encapsulate all of the vertex transfer state necessary to
-                    render objects.</para>
+                <para>Vertex array objects encapsulate all of the state necessary to render objects.
+                    This includes vertex attribute arrays, buffer objects to feed those arrays, and
+                    the element buffer, if present.</para>
             </listitem>
             <listitem>
                 <para>Indexed rendering pulls data from the current vertex arrays by using a

Tut 05 Objects in Depth/BaseVertexOverlap.cpp

 	glUseProgram(0);
 
 	glutSwapBuffers();
-	glutPostRedisplay();
 }
 
 //Called whenever the window is resized. The new window size is given, in pixels.

Tut 05 Objects in Depth/DepthBuffer.cpp

 	glUseProgram(0);
 
 	glutSwapBuffers();
-	glutPostRedisplay();
 }
 
 //Called whenever the window is resized. The new window size is given, in pixels.

Tut 05 Objects in Depth/DepthClamping.cpp

 	glUseProgram(0);
 
 	glutSwapBuffers();
-	glutPostRedisplay();
 }
 
 //Called whenever the window is resized. The new window size is given, in pixels.
 			glEnable(GL_DEPTH_CLAMP);
 
 		bDepthClampingActive = !bDepthClampingActive;
+		glutPostRedisplay();
 		break;
 	}
 }

Tut 05 Objects in Depth/OverlapNoDepth.cpp

 	glUseProgram(0);
 
 	glutSwapBuffers();
-	glutPostRedisplay();
 }
 
 //Called whenever the window is resized. The new window size is given, in pixels.

Tut 05 Objects in Depth/VertexClipping.cpp

 	glUseProgram(0);
 
 	glutSwapBuffers();
-	glutPostRedisplay();
 }
 
 //Called whenever the window is resized. The new window size is given, in pixels.

Tut 06 Objects in Motion/Rotations.cpp

+#include <string>
+#include <vector>
+#include <math.h>
+#include <glloader/gl_3_2_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.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*))))
+
+GLuint theProgram;
+GLuint positionAttrib;
+GLuint colorAttrib;
+
+GLuint modelToCameraMatrixUnif;
+GLuint cameraToClipMatrixUnif;
+
+glm::mat4 cameraToClipMatrix(0.0f);
+
+float CalcFrustumScale(float fFovDeg)
+{
+	const float degToRad = 3.14159f * 2.0f / 360.0f;
+	float fFovRad = fFovDeg * degToRad;
+	return 1.0f / tan(fFovRad / 2.0f);
+}
+
+const float fFrustumScale = CalcFrustumScale(45.0f);
+
+void InitializeProgram()
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, "PosColorLocalTransform.vert"));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, "Standard.frag"));
+
+	theProgram = Framework::CreateProgram(shaderList);
+
+	positionAttrib = glGetAttribLocation(theProgram, "position");
+	colorAttrib = glGetAttribLocation(theProgram, "color");
+
+	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
+	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
+
+	float fzNear = 1.0f; float fzFar = 45.0f;
+
+	cameraToClipMatrix[0].x = fFrustumScale;
+	cameraToClipMatrix[1].y = fFrustumScale;
+	cameraToClipMatrix[2].z = (fzFar + fzNear) / (fzNear - fzFar);
+	cameraToClipMatrix[2].w = -1.0f;
+	cameraToClipMatrix[3].z = (2 * fzFar * fzNear) / (fzNear - fzFar);
+
+	glUseProgram(theProgram);
+	glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
+	glUseProgram(0);
+}
+
+const int numberOfVertices = 8;
+
+#define GREEN_COLOR 0.75f, 0.75f, 1.0f, 1.0f
+#define BLUE_COLOR 	0.0f, 0.5f, 0.0f, 1.0f
+#define RED_COLOR 1.0f, 0.0f, 0.0f, 1.0f
+#define GREY_COLOR 0.8f, 0.8f, 0.8f, 1.0f
+#define BROWN_COLOR 0.5f, 0.5f, 0.0f, 1.0f
+
+const float vertexData[] =
+{
+	+1.0f, +1.0f, +1.0f,
+	-1.0f, -1.0f, +1.0f,
+	-1.0f, +1.0f, -1.0f,
+	+1.0f, -1.0f, -1.0f,
+
+	-1.0f, -1.0f, -1.0f,
+	+1.0f, +1.0f, -1.0f,
+	+1.0f, -1.0f, +1.0f,
+	-1.0f, +1.0f, +1.0f,
+
+	GREEN_COLOR,
+	BLUE_COLOR,
+	RED_COLOR,
+	BROWN_COLOR,
+
+	GREEN_COLOR,
+	BLUE_COLOR,
+	RED_COLOR,
+	BROWN_COLOR,
+};
+
+const GLshort indexData[] =
+{
+	0, 1, 2,
+	1, 0, 3,
+	2, 3, 0,
+	3, 2, 1,
+
+	5, 4, 6,
+	4, 5, 7,
+	7, 6, 4,
+	6, 7, 5,
+};
+
+GLuint vertexBufferObject;
+GLuint indexBufferObject;
+GLuint vao;
+
+
+void InitializeVertexBuffer()
+{
+	glGenBuffers(1, &vertexBufferObject);
+
+	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+	glGenBuffers(1, &indexBufferObject);
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+glm::vec3 StationaryOffset(float fElapsedTime)
+{
+	return glm::vec3(0.0f, 0.0f, -20.0f);
+}
+
+glm::vec3 OvalOffset(float fElapsedTime)
+{
+	const float fLoopDuration = 3.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
+
+	return glm::vec3(cosf(fCurrTimeThroughLoop * fScale) * 4.f,
+		sinf(fCurrTimeThroughLoop * fScale) * 6.f,
+		-20.0f);
+}
+
+glm::vec3 BottomCircleOffset(float fElapsedTime)
+{
+	const float fLoopDuration = 12.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
+
+	return glm::vec3(cosf(fCurrTimeThroughLoop * fScale) * 5.f,
+		-3.5f,
+		sinf(fCurrTimeThroughLoop * fScale) * 5.f - 20.0f);
+}
+
+struct Instance
+{
+	typedef glm::vec3(*OffsetFunc)(float);
+
+	glm::vec3 scale;
+	OffsetFunc CalcOffset;
+
+	glm::mat4 ConstructMatrix(float fElapsedTime)
+	{
+		glm::mat4 theMat(1.0f);
+		theMat[0].x = scale.x;
+		theMat[1].y = scale.y;
+		theMat[2].z = scale.z;
+
+		theMat[3] = glm::vec4(CalcOffset(fElapsedTime), 1.0f);
+
+		return theMat;
+	}
+};
+
+Instance g_instanceList[] =
+{
+	{glm::vec3(1.0f, 1.0f, 1.0f), StationaryOffset},
+	{glm::vec3(0.5f, 1.5f, 0.5f), OvalOffset},
+	{glm::vec3(0.5f, 1.0f, 0.5f), BottomCircleOffset},
+};
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+	InitializeVertexBuffer();
+
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
+	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
+	glEnableVertexAttribArray(positionAttrib);
+	glEnableVertexAttribArray(colorAttrib);
+	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
+	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
+
+	glBindVertexArray(0);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(0.0f, 1.0f);
+}
+
+//Called to update the display.
+//You should call glutSwapBuffers after all of your rendering to display what you rendered.
+//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
+void display()
+{
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	glUseProgram(theProgram);
+
+	glBindVertexArray(vao);
+
+	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
+	for(int iLoop = 0; iLoop < ARRAY_COUNT(g_instanceList); iLoop++)
+	{
+		Instance &currInst = g_instanceList[iLoop];
+		const glm::mat4 &transformMatrix = currInst.ConstructMatrix(fElapsedTime);
+
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(transformMatrix));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+	}
+
+	glBindVertexArray(0);
+	glUseProgram(0);
+
+	glutSwapBuffers();
+	glutPostRedisplay();
+}
+
+//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)
+{
+	cameraToClipMatrix[0].x = fFrustumScale * (h / (float)w);
+	cameraToClipMatrix[1].y = fFrustumScale;
+
+	glUseProgram(theProgram);
+	glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
+	glUseProgram(0);
+
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+}
+
+//Called whenever a key on the keyboard was pressed.
+//The key is given by the ''key'' parameter, which is in ASCII.
+//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
+//exit the program.
+void keyboard(unsigned char key, int x, int y)
+{
+	switch (key)
+	{
+	case 27:
+		glutLeaveMainLoop();
+		break;
+	}
+}
+
+

Tut 06 Objects in Motion/TranslationScale.cpp

+#include <string>
+#include <vector>
+#include <math.h>
+#include <glloader/gl_3_2_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.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*))))
+
+GLuint theProgram;
+GLuint positionAttrib;
+GLuint colorAttrib;
+
+GLuint modelToCameraMatrixUnif;
+GLuint cameraToClipMatrixUnif;
+
+glm::mat4 cameraToClipMatrix(0.0f);
+
+float CalcFrustumScale(float fFovDeg)
+{
+	const float degToRad = 3.14159f * 2.0f / 360.0f;
+	float fFovRad = fFovDeg * degToRad;
+	return 1.0f / tan(fFovRad / 2.0f);
+}
+
+const float fFrustumScale = CalcFrustumScale(45.0f);
+
+void InitializeProgram()
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, "PosColorLocalTransform.vert"));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, "Standard.frag"));
+
+	theProgram = Framework::CreateProgram(shaderList);
+
+	positionAttrib = glGetAttribLocation(theProgram, "position");
+	colorAttrib = glGetAttribLocation(theProgram, "color");
+
+	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
+	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
+
+	float fzNear = 1.0f; float fzFar = 45.0f;
+
+	cameraToClipMatrix[0].x = fFrustumScale;
+	cameraToClipMatrix[1].y = fFrustumScale;
+	cameraToClipMatrix[2].z = (fzFar + fzNear) / (fzNear - fzFar);
+	cameraToClipMatrix[2].w = -1.0f;
+	cameraToClipMatrix[3].z = (2 * fzFar * fzNear) / (fzNear - fzFar);
+
+	glUseProgram(theProgram);
+	glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
+	glUseProgram(0);
+}
+
+const int numberOfVertices = 8;
+
+#define GREEN_COLOR 0.75f, 0.75f, 1.0f, 1.0f
+#define BLUE_COLOR 	0.0f, 0.5f, 0.0f, 1.0f
+#define RED_COLOR 1.0f, 0.0f, 0.0f, 1.0f
+#define GREY_COLOR 0.8f, 0.8f, 0.8f, 1.0f
+#define BROWN_COLOR 0.5f, 0.5f, 0.0f, 1.0f
+
+const float vertexData[] =
+{
+	+1.0f, +1.0f, +1.0f,
+	-1.0f, -1.0f, +1.0f,
+	-1.0f, +1.0f, -1.0f,
+	+1.0f, -1.0f, -1.0f,
+
+	-1.0f, -1.0f, -1.0f,
+	+1.0f, +1.0f, -1.0f,
+	+1.0f, -1.0f, +1.0f,
+	-1.0f, +1.0f, +1.0f,
+
+	GREEN_COLOR,
+	BLUE_COLOR,
+	RED_COLOR,
+	BROWN_COLOR,
+
+	GREEN_COLOR,
+	BLUE_COLOR,
+	RED_COLOR,
+	BROWN_COLOR,
+};
+
+const GLshort indexData[] =
+{
+	0, 1, 2,
+	1, 0, 3,
+	2, 3, 0,
+	3, 2, 1,
+
+	5, 4, 6,
+	4, 5, 7,
+	7, 6, 4,
+	6, 7, 5,
+};
+
+GLuint vertexBufferObject;
+GLuint indexBufferObject;
+GLuint vao;
+
+
+void InitializeVertexBuffer()
+{
+	glGenBuffers(1, &vertexBufferObject);
+
+	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+	glGenBuffers(1, &indexBufferObject);
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+glm::vec3 StationaryOffset(float fElapsedTime)
+{
+	return glm::vec3(0.0f, 0.0f, -20.0f);
+}
+
+glm::vec3 OvalOffset(float fElapsedTime)
+{
+	const float fLoopDuration = 3.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
+
+	return glm::vec3(cosf(fCurrTimeThroughLoop * fScale) * 4.f,
+		sinf(fCurrTimeThroughLoop * fScale) * 6.f,
+		-20.0f);
+}
+
+glm::vec3 BottomCircleOffset(float fElapsedTime)
+{
+	const float fLoopDuration = 12.0f;
+	const float fScale = 3.14159f * 2.0f / fLoopDuration;
+
+	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
+
+	return glm::vec3(cosf(fCurrTimeThroughLoop * fScale) * 5.f,
+		-3.5f,
+		sinf(fCurrTimeThroughLoop * fScale) * 5.f - 20.0f);
+}
+
+struct Instance
+{
+	typedef glm::vec3(*OffsetFunc)(float);
+
+	glm::vec3 scale;
+	OffsetFunc CalcOffset;
+
+	glm::mat4 ConstructMatrix(float fElapsedTime)
+	{
+		glm::mat4 theMat(1.0f);
+		theMat[0].x = scale.x;
+		theMat[1].y = scale.y;
+		theMat[2].z = scale.z;
+
+		theMat[3] = glm::vec4(CalcOffset(fElapsedTime), 1.0f);
+
+		return theMat;
+	}
+};
+
+Instance g_instanceList[] =
+{
+	{glm::vec3(1.0f, 1.0f, 1.0f), StationaryOffset},
+	{glm::vec3(0.5f, 1.5f, 0.5f), OvalOffset},
+	{glm::vec3(0.5f, 1.0f, 0.5f), BottomCircleOffset},
+};
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+	InitializeVertexBuffer();
+
+	glGenVertexArrays(1, &vao);
+	glBindVertexArray(vao);
+
+	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
+	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
+	glEnableVertexAttribArray(positionAttrib);
+	glEnableVertexAttribArray(colorAttrib);
+	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
+	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
+
+	glBindVertexArray(0);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(0.0f, 1.0f);
+}
+
+//Called to update the display.
+//You should call glutSwapBuffers after all of your rendering to display what you rendered.
+//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
+void display()
+{
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	glUseProgram(theProgram);
+
+	glBindVertexArray(vao);
+
+	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
+	for(int iLoop = 0; iLoop < ARRAY_COUNT(g_instanceList); iLoop++)
+	{
+		Instance &currInst = g_instanceList[iLoop];
+		const glm::mat4 &transformMatrix = currInst.ConstructMatrix(fElapsedTime);
+
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(transformMatrix));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+	}
+
+	glBindVertexArray(0);
+	glUseProgram(0);
+
+	glutSwapBuffers();
+	glutPostRedisplay();
+}
+
+//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)
+{
+	cameraToClipMatrix[0].x = fFrustumScale * (h / (float)w);
+	cameraToClipMatrix[1].y = fFrustumScale;
+
+	glUseProgram(theProgram);
+	glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
+	glUseProgram(0);
+
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+}
+
+//Called whenever a key on the keyboard was pressed.
+//The key is given by the ''key'' parameter, which is in ASCII.
+//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
+//exit the program.
+void keyboard(unsigned char key, int x, int y)
+{
+	switch (key)
+	{
+	case 27:
+		glutLeaveMainLoop();
+		break;
+	}
+}
+
+

Tut 06 Objects in Motion/data/ColorPassthrough.frag

+#version 150
+
+smooth in vec4 theColor;
+
+out vec4 outputColor;
+
+void main()
+{
+	outputColor = theColor;
+}

Tut 06 Objects in Motion/data/PosColorLocalTransform.vert

+#version 150
+
+in vec4 position;
+in vec4 color;
+
+smooth out vec4 theColor;
+
+uniform mat4 cameraToClipMatrix;
+uniform mat4 modelToCameraMatrix;
+
+void main()
+{
+	vec4 cameraPos = modelToCameraMatrix * position;
+	gl_Position = cameraToClipMatrix * cameraPos;
+	theColor = color;
+}

Tut 06 Objects in Motion/premake4.lua

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

Tut 06 Objects in Motion/tutorials.lua

+
+SetupProject("Translation Scale", "TranslationScale.cpp",
+	"data/ColorPassthrough.frag", "data/PosColorLocalTransform.vert")
+SetupProject("Rotations", "Rotations.cpp",
+	"data/ColorPassthrough.frag", "data/PosColorLocalTransform.vert")

framework/framework.lua

 		files {...}
 		targetdir "bin"
 
-		includedirs "../freeglut-2.6.0/include"
-		includedirs "../glloader/include"
-		includedirs "../FreeImage/dist"
+		includedirs {"../freeglut-2.6.0/include", "../glloader/include",
+			"../FreeImage/dist", "../glm-0.9.0.0"}
 
 		configuration "Debug"
 			defines {"DEBUG", "_DEBUG"}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.