Jason McKesson avatar Jason McKesson committed 6feca88

Tut08: Finished source code.
Added a timer to the framework.

Comments (0)

Files changed (9)

Tut 08 Getting Oriented/CameraRelative.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 <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/quaternion.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;
+GLuint baseColorUnif;
+
+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(20.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, "ColorMultUniform.frag"));
+
+	theProgram = Framework::CreateProgram(shaderList);
+
+	positionAttrib = glGetAttribLocation(theProgram, "position");
+	colorAttrib = glGetAttribLocation(theProgram, "color");
+
+	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
+	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
+	baseColorUnif = glGetUniformLocation(theProgram, "baseColor");
+
+	float fzNear = 1.0f; float fzFar = 600.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);
+}
+
+Framework::Mesh *g_pShip = NULL;
+Framework::Mesh *g_pPlane = NULL;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+
+	try
+	{
+		g_pShip = new Framework::Mesh("Ship.xml");
+		g_pPlane = new Framework::Mesh("UnitPlane.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+
+	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);
+}
+
+struct GimbalAngles
+{
+	GimbalAngles()
+		: fAngleX(0.0f)
+		, fAngleY(0.0f)
+		, fAngleZ(0.0f)
+	{}
+
+	float fAngleX;
+	float fAngleY;
+	float fAngleZ;
+};
+
+GimbalAngles g_angles;
+static glm::vec3 g_camTarget(0.0f, 10.0f, 0.0f);
+static glm::fquat g_orientation(1.0f, 0.0f, 0.0f, 0.0f);
+
+//In spherical coordinates.
+static glm::vec3 g_sphereCamRelPos(90.0f, 0.0f, 66.0f);
+
+glm::vec3 ResolveCamPosition()
+{
+	Framework::MatrixStack tempMat;
+
+	float rho = Framework::DegToRad(g_sphereCamRelPos.x);
+	float theta = Framework::DegToRad(g_sphereCamRelPos.y + 90.0f);
+
+	float fSinTheta = sinf(theta);
+	float fCosTheta = cosf(theta);
+	float fCosRho = cosf(rho);
+	float fSinRho = sinf(rho);
+
+	glm::vec3 dirToCamera(fSinTheta * fCosRho, fCosTheta, fSinTheta * fSinRho);
+	return (dirToCamera * g_sphereCamRelPos.z) + g_camTarget;
+}
+
+glm::mat4 CalcLookAtMatrix(const glm::vec3 &cameraPt, const glm::vec3 &lookPt, const glm::vec3 &upPt)
+{
+	glm::vec3 lookDir = glm::normalize(lookPt - cameraPt);
+	glm::vec3 upDir = glm::normalize(upPt);
+
+	glm::vec3 rightDir = glm::normalize(glm::cross(lookDir, upDir));
+	glm::vec3 perpUpDir = glm::cross(rightDir, lookDir);
+
+	glm::mat4 rotMat(1.0f);
+	rotMat[0] = glm::vec4(rightDir, 0.0f);
+	rotMat[1] = glm::vec4(perpUpDir, 0.0f);
+	rotMat[2] = glm::vec4(-lookDir, 0.0f);
+
+	rotMat = glm::transpose(rotMat);
+
+	glm::mat4 transMat(1.0f);
+	transMat[3] = glm::vec4(-cameraPt, 1.0f);
+
+	return rotMat * transMat;
+}
+
+
+//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);
+
+	Framework::MatrixStack currMatrix;
+	const glm::vec3 &camPos = ResolveCamPosition();
+	currMatrix.SetMatrix(CalcLookAtMatrix(camPos, g_camTarget, glm::vec3(0.0f, 1.0f, 0.0f)));
+
+	glUseProgram(theProgram);
+
+	{
+		Framework::MatrixStackPusher stack(currMatrix);
+		currMatrix.Scale(100.0f, 1.0f, 100.0f);
+
+		glUniform4f(baseColorUnif, 0.2f, 0.5f, 0.2f, 1.0f);
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
+
+		g_pPlane->Render();
+	}
+
+	{
+		Framework::MatrixStackPusher stack(currMatrix);
+		currMatrix.Translate(g_camTarget);
+		currMatrix.ApplyMatrix(glm::mat4_cast(g_orientation));
+		currMatrix.RotateX(-90);
+
+		//Set the base color for this object.
+		glUniform4f(baseColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
+
+		g_pShip->Render("tint");
+	}
+
+	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);
+}
+
+#define SMALL_ANGLE_INCREMENT 9.0f
+
+enum OffsetRelative
+{
+	MODEL_RELATIVE,
+	WORLD_RELATIVE,
+	CAMERA_RELATIVE,
+
+	NUM_RELATIVES,
+};
+
+static int g_iOffset = MODEL_RELATIVE;
+
+void OffsetOrientation(const glm::vec3 &_axis, float fAngDeg)
+{
+	float fAngRad = Framework::DegToRad(fAngDeg);
+
+	glm::vec3 axis = glm::normalize(_axis);
+
+	axis = axis * sinf(fAngRad / 2.0f);
+	float scalar = cosf(fAngRad / 2.0f);
+
+	glm::fquat offset(scalar, axis.x, axis.y, axis.z);
+
+	switch(g_iOffset)
+	{
+	case MODEL_RELATIVE:
+		g_orientation = g_orientation * offset;
+		break;
+	case WORLD_RELATIVE:
+		g_orientation = offset * g_orientation;
+		break;
+	case CAMERA_RELATIVE:
+		{
+			const glm::vec3 &camPos = ResolveCamPosition();
+			const glm::mat4 &camMat = CalcLookAtMatrix(camPos, g_camTarget, glm::vec3(0.0f, 1.0f, 0.0f));
+
+			glm::fquat viewQuat = glm::quat_cast(camMat);
+			glm::fquat invViewQuat = glm::conjugate(viewQuat);
+
+			const glm::fquat &worldQuat = (invViewQuat * offset * viewQuat);
+			g_orientation = worldQuat * g_orientation;
+		}
+		break;
+	}
+
+	g_orientation = glm::normalize(g_orientation);
+}
+
+
+//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;
+	case 'w': OffsetOrientation(glm::vec3(1.0f, 0.0f, 0.0f), SMALL_ANGLE_INCREMENT); break;
+	case 's': OffsetOrientation(glm::vec3(1.0f, 0.0f, 0.0f), -SMALL_ANGLE_INCREMENT); break;
+
+	case 'a': OffsetOrientation(glm::vec3(0.0f, 0.0f, 1.0f), SMALL_ANGLE_INCREMENT); break;
+	case 'd': OffsetOrientation(glm::vec3(0.0f, 0.0f, 1.0f), -SMALL_ANGLE_INCREMENT); break;
+
+	case 'q': OffsetOrientation(glm::vec3(0.0f, 1.0f, 0.0f), SMALL_ANGLE_INCREMENT); break;
+	case 'e': OffsetOrientation(glm::vec3(0.0f, 1.0f, 0.0f), -SMALL_ANGLE_INCREMENT); break;
+	case 32:
+		g_iOffset += 1;
+		g_iOffset = g_iOffset % NUM_RELATIVES;
+		{
+			switch(g_iOffset)
+			{
+			case MODEL_RELATIVE: printf("Model Relative\n"); break;
+			case WORLD_RELATIVE: printf("World Relative\n"); break;
+			case CAMERA_RELATIVE: printf("Camera Relative\n"); break;
+			}
+		}
+		break;
+	case 'i': g_sphereCamRelPos.y -= 11.25f; break;
+	case 'k': g_sphereCamRelPos.y += 11.25f; break;
+	case 'j': g_sphereCamRelPos.x -= 11.25f; break;
+	case 'l': g_sphereCamRelPos.x += 11.25f; break;
+	case 'I': g_sphereCamRelPos.y -= 1.125f; break;
+	case 'K': g_sphereCamRelPos.y += 1.125f; break;
+	case 'J': g_sphereCamRelPos.x -= 1.125f; break;
+	case 'L': g_sphereCamRelPos.x += 1.125f; break;
+	}
+
+	g_sphereCamRelPos.y = glm::clamp(g_sphereCamRelPos.y, -78.75f, 10.0f);
+}
+
+

Tut 08 Getting Oriented/GimbalLock.cpp

 			g_Gimbals[iLoop] = new Framework::Mesh(g_strGimbalNames[iLoop]);
 		}
 
-		g_pObject = new Framework::Mesh("test.xml");
+		g_pObject = new Framework::Mesh("Ship.xml");
 	}
 	catch(std::exception &except)
 	{

Tut 08 Getting Oriented/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/Timer.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/quaternion.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;
+GLuint baseColorUnif;
+
+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(20.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, "ColorMultUniform.frag"));
+
+	theProgram = Framework::CreateProgram(shaderList);
+
+	positionAttrib = glGetAttribLocation(theProgram, "position");
+	colorAttrib = glGetAttribLocation(theProgram, "color");
+
+	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
+	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
+	baseColorUnif = glGetUniformLocation(theProgram, "baseColor");
+
+	float fzNear = 1.0f; float fzFar = 600.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);
+}
+
+Framework::Mesh *g_pShip = NULL;
+
+static glm::fquat g_Orients[] =
+{
+	glm::fquat(0.7071f, 0.7071f, 0.0f, 0.0f),
+	glm::fquat(0.5f, 0.5f, -0.5f, 0.5f),
+	glm::fquat(0.5537f, 0.5208f, 0.6483f, 0.0410f),
+	glm::fquat(-0.4895f, -0.7892f, -0.3700f, -0.02514f),
+	glm::fquat(0.0f, 0.0f, 1.0f, 0.0f),
+	glm::fquat(0.3840f, -0.1591f, -0.7991f, -0.4344f),
+};
+
+static char g_OrientKeys[] =
+{
+	'z',
+	'x',
+	'c',
+	'v',
+	'b',
+	'n',
+};
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+
+	try
+	{
+		g_pShip = new Framework::Mesh("Ship.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+	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);
+}
+
+glm::vec4 Vectorize(const glm::fquat theQuat)
+{
+	glm::vec4 ret;
+
+	ret.x = theQuat.x;
+	ret.y = theQuat.y;
+	ret.z = theQuat.z;
+	ret.w = theQuat.w;
+
+	return ret;
+}
+
+class Orientation
+{
+public:
+	Orientation()
+		: m_bIsAnimating(false)
+		, m_ixCurrOrient(0)
+		, m_bSlerp(false)
+	{}
+
+	bool ToggleSlerp()
+	{
+		m_bSlerp = !m_bSlerp;
+		return m_bSlerp;
+	}
+
+	glm::fquat GetOrient() const
+	{
+		if(m_bIsAnimating)
+			return m_anim.GetOrient(g_Orients[m_ixCurrOrient], m_bSlerp);
+		else
+			return g_Orients[m_ixCurrOrient];
+	}
+
+	bool IsAnimating() const {return m_bIsAnimating;}
+
+	void UpdateTime()
+	{
+		if(m_bIsAnimating)
+		{
+			bool bIsFinished = m_anim.UpdateTime();
+			if(bIsFinished)
+			{
+				m_bIsAnimating = false;
+				m_ixCurrOrient = m_anim.GetFinalIx();
+			}
+		}
+	}
+
+	void AnimateToOrient(int ixDestination)
+	{
+		if(m_ixCurrOrient == ixDestination)
+			return;
+
+		m_anim.StartAnimation(ixDestination, 1.0f);
+		m_bIsAnimating = true;
+	}
+
+private:
+	class Animation
+	{
+	public:
+		//Returns true if the animation is over.
+		bool UpdateTime()
+		{
+			return m_currTimer.Update();
+		}
+
+		glm::fquat GetOrient(const glm::fquat &initial, bool bSlerp) const
+		{
+			if(bSlerp)
+			{
+				return glm::mix(initial, g_Orients[m_ixFinalOrient], m_currTimer.GetAlpha());
+			}
+			else
+			{
+				glm::vec4 start = Vectorize(initial);
+				glm::vec4 end = Vectorize(g_Orients[m_ixFinalOrient]);
+				glm::vec4 interp = glm::mix(start, end, m_currTimer.GetAlpha());
+				interp = glm::normalize(interp);
+				return glm::fquat(interp.w, interp.x, interp.y, interp.z);
+			}
+
+			return initial;
+		}
+
+		void StartAnimation(int ixDestination, float fDuration)
+		{
+			m_ixFinalOrient = ixDestination;
+			m_currTimer = Framework::Timer(Framework::Timer::TT_SINGLE, fDuration);
+		}
+
+		int GetFinalIx() const {return m_ixFinalOrient;}
+
+	private:
+		int m_ixFinalOrient;
+		Framework::Timer m_currTimer;
+	};
+
+	bool m_bIsAnimating;
+	int m_ixCurrOrient;
+	bool m_bSlerp;
+
+	Animation m_anim;
+};
+
+Orientation g_orient;
+
+class Animation
+{
+public:
+
+private:
+	glm::fquat m_finalOrient;
+};
+
+//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()
+{
+	g_orient.UpdateTime();
+
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	Framework::MatrixStack currMatrix;
+	currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
+	currMatrix.ApplyMatrix(glm::mat4_cast(g_orient.GetOrient()));
+
+	glUseProgram(theProgram);
+	currMatrix.Scale(3.0, 3.0, 3.0);
+	currMatrix.RotateX(-90);
+	//Set the base color for this object.
+	glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
+	glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
+
+	g_pShip->Render("tint");
+
+	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);
+}
+
+void ApplyOrientation(int iIndex)
+{
+	if(!g_orient.IsAnimating())
+		g_orient.AnimateToOrient(iIndex);
+}
+
+
+//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;
+	case 32:
+		{
+			bool bSlerp = g_orient.ToggleSlerp();
+			printf(bSlerp ? "Slerp\n" : "Lerp\n");
+		}
+		break;
+	}
+
+	for(int iOrient = 0; iOrient < ARRAY_COUNT(g_OrientKeys); iOrient++)
+	{
+		if(key == g_OrientKeys[iOrient])
+			ApplyOrientation(iOrient);
+	}
+}
+
+

Tut 08 Getting Oriented/QuaternionYPR.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 <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/quaternion.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;
+GLuint baseColorUnif;
+
+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(20.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, "ColorMultUniform.frag"));
+
+	theProgram = Framework::CreateProgram(shaderList);
+
+	positionAttrib = glGetAttribLocation(theProgram, "position");
+	colorAttrib = glGetAttribLocation(theProgram, "color");
+
+	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
+	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
+	baseColorUnif = glGetUniformLocation(theProgram, "baseColor");
+
+	float fzNear = 1.0f; float fzFar = 600.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);
+}
+
+Framework::Mesh *g_pShip = NULL;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+
+	try
+	{
+		g_pShip = new Framework::Mesh("Ship.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
+
+
+	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);
+}
+
+struct GimbalAngles
+{
+	GimbalAngles()
+		: fAngleX(0.0f)
+		, fAngleY(0.0f)
+		, fAngleZ(0.0f)
+	{}
+
+	float fAngleX;
+	float fAngleY;
+	float fAngleZ;
+};
+
+GimbalAngles g_angles;
+glm::fquat g_orientation(1.0f, 0.0f, 0.0f, 0.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);
+
+	Framework::MatrixStack currMatrix;
+	currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
+	currMatrix.ApplyMatrix(glm::mat4_cast(g_orientation));
+
+	glUseProgram(theProgram);
+	currMatrix.Scale(3.0, 3.0, 3.0);
+	currMatrix.RotateX(-90);
+	//Set the base color for this object.
+	glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
+	glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
+
+	g_pShip->Render("tint");
+
+	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);
+}
+
+#define SMALL_ANGLE_INCREMENT 9.0f
+
+static bool g_bPreMultiply = true;
+
+void OffsetOrientation(const glm::vec3 &_axis, float fAngDeg)
+{
+	float fAngRad = Framework::DegToRad(fAngDeg);
+
+	glm::vec3 axis = glm::normalize(_axis);
+
+	axis = axis * sinf(fAngRad / 2.0f);
+	float scalar = cosf(fAngRad / 2.0f);
+
+	glm::fquat offset(scalar, axis.x, axis.y, axis.z);
+
+	if(g_bPreMultiply)
+		g_orientation = g_orientation * offset;
+	else
+		g_orientation = offset * g_orientation;
+
+	g_orientation = glm::normalize(g_orientation);
+}
+
+
+//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;
+	case 'w': OffsetOrientation(glm::vec3(1.0f, 0.0f, 0.0f), SMALL_ANGLE_INCREMENT); break;
+	case 's': OffsetOrientation(glm::vec3(1.0f, 0.0f, 0.0f), -SMALL_ANGLE_INCREMENT); break;
+
+	case 'a': OffsetOrientation(glm::vec3(0.0f, 0.0f, 1.0f), SMALL_ANGLE_INCREMENT); break;
+	case 'd': OffsetOrientation(glm::vec3(0.0f, 0.0f, 1.0f), -SMALL_ANGLE_INCREMENT); break;
+
+	case 'q': OffsetOrientation(glm::vec3(0.0f, 1.0f, 0.0f), SMALL_ANGLE_INCREMENT); break;
+	case 'e': OffsetOrientation(glm::vec3(0.0f, 1.0f, 0.0f), -SMALL_ANGLE_INCREMENT); break;
+	case 32:
+		g_bPreMultiply = !g_bPreMultiply;
+		printf(g_bPreMultiply ? "Pre-multiply\n" : "Post-multiply\n");
+		break;
+	}
+}
+
+

Tut 08 Getting Oriented/data/GenPlane.lua

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

Tut 08 Getting Oriented/data/UnitPlane.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="../../Documents/meshFormat.rnc" type="compact"?>
+
+<mesh xmlns="http://www.arcsynthesis.com/gltut/mesh" >
+	<attribute index="0" type="float" size="3" > 
+        0.5 0 -0.5
+        0.5 0 0.5
+        -0.5 0 0.5
+        -0.5 0 -0.5</attribute>
+	<attribute index="1" type="float" size="4" > 
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1</attribute>
+	<indices cmd="triangles" type="ushort" > 
+        0 1 2
+        0 2 1
+        2 3 0
+        2 0 3</indices>
+</mesh>

Tut 08 Getting Oriented/tutorials.lua

 
 SetupProject("Tut 08 Gimbal Lock", "GimbalLock.cpp",
 	"data/ColorMultUniform.frag", "data/PosColorLocalTransform.vert")
+
+SetupProject("Tut 08 Quaternion YPR", "QuaternionYPR.cpp",
+	"data/ColorMultUniform.frag", "data/PosColorLocalTransform.vert")
+
+SetupProject("Tut 08 Camera Relative", "CameraRelative.cpp",
+	"data/ColorMultUniform.frag", "data/PosColorLocalTransform.vert")
+
+SetupProject("Tut 08 Interpolation", "Interpolation.cpp",
+	"data/ColorMultUniform.frag", "data/PosColorLocalTransform.vert")
+

framework/Timer.cpp

+
+
+#include <math.h>
+#include <glm/glm.hpp>
+#include <GL/freeglut.h>
+#include "framework.h"
+#include "Timer.h"
+
+
+
+namespace Framework
+{
+	Timer::Timer( Type eType, float fDuration )
+		: m_eType(eType)
+		, m_fDuration(fDuration)
+		, m_bHasUpdated(false)
+		, m_bIsPaused(false)
+		, m_absPrevTime(0.0f)
+		, m_fAccumTime(0.0f)
+	{
+		if(m_eType != TT_INFINITE)
+			assert(m_fDuration > 0.0f);
+	}
+
+	void Timer::Reset()
+	{
+		m_bHasUpdated = false;
+		m_fAccumTime = 0.0f;
+	}
+
+	bool Timer::TogglePause()
+	{
+		m_bIsPaused = !m_bIsPaused;
+		return m_bIsPaused;
+	}
+
+	bool Timer::Update()
+	{
+		float absCurrTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
+		if(!m_bHasUpdated)
+		{
+			m_absPrevTime = absCurrTime;
+			m_bHasUpdated = true;
+		}
+
+		if(m_bIsPaused)
+		{
+			m_absPrevTime = absCurrTime;
+			return false;
+		}
+
+		float fDeltaTime = absCurrTime - m_absPrevTime;
+		m_fAccumTime += fDeltaTime;
+
+		m_absPrevTime = absCurrTime;
+		if(m_eType == TT_SINGLE)
+			return m_fAccumTime > m_fDuration;
+
+		return false;
+	}
+
+	float Timer::GetAlpha() const
+	{
+		switch(m_eType)
+		{
+		case TT_LOOP:
+			return fmodf(m_fAccumTime, m_fDuration);
+		case TT_SINGLE:
+			return glm::clamp(m_fAccumTime / m_fDuration, 0.0f, 1.0f);
+		}
+
+		return -1.0f;	//Garbage.
+	}
+
+	float Timer::GetProgression() const
+	{
+		switch(m_eType)
+		{
+		case TT_LOOP:
+			return fmodf(m_fAccumTime, m_fDuration) * m_fDuration;
+		case TT_SINGLE:
+			return glm::clamp(m_fAccumTime, 0.0f, m_fDuration);
+		}
+
+		return -1.0f;	//Garbage.
+	}
+
+	float Timer::GetTimeSinceStart() const
+	{
+		return m_fAccumTime;
+	}
+}

framework/Timer.h

+
+#ifndef FRAMEWORK_TIMER_H
+#define FRAMEWORK_TIMER_H
+
+namespace Framework
+{
+	class Timer
+	{
+	public:
+		enum Type
+		{
+			TT_LOOP,
+			TT_SINGLE,
+			TT_INFINITE,
+
+			NUM_TIMER_TYPES,
+		};
+
+		/**
+		Creates a timer with the given type.
+
+		LOOP and SINGLE timers need an explicit duration. This represents the time in seconds
+		through a loop, or the time in seconds until the timer expires.
+
+		INFINITE timers ignore the duration.
+		**/
+		Timer(Type eType = TT_INFINITE, float fDuration = 1.0f);
+
+		//Resets the timer, as though the user just created the object with the original parameters.
+		void Reset();
+
+		//Pauses/unpauses. Returns true if the timer is paused.
+		bool TogglePause();
+
+		//Updates the time for the timer. Returns true if the timer has reached the end.
+		//Will only return true for SINGLE timers that have reached their duration.
+		bool Update();
+
+		//Returns a number [0, 1], representing progress through the duration. Only used
+		//for SINGLE and LOOP timers.
+		float GetAlpha() const;
+
+		//Returns a number [0, duration], representing the progress through the timer in 
+		//seconds. Only for SINGLE and LOOP timers.
+		float GetProgression() const;
+
+		//Returns the time in seconds since the timer was started, excluding
+		//time for pausing.
+		float GetTimeSinceStart() const;
+
+	private:
+		Type m_eType;
+		float m_fDuration;
+
+		bool m_bHasUpdated;
+		bool m_bIsPaused;
+
+		float m_absPrevTime;
+		float m_fAccumTime;
+	};
+}
+
+
+#endif //FRAMEWORK_TIMER_H
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.